contentの解析
>>> response.content.splitlines()[0]
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
- HTML: BeautifulSoup , lxml ...
- XML: gnosis ...
- JSON: simplejson ...
⋙Start Presentation via s6 by amachang.
Django勉強会 Disk 4 でプレゼンした資料です。
MiCHiLU
takanao at endoh dot tk
2007-08-25
Test Driven Development
チェンジセットにTESTが含まれてればいい
あとから書いてもいいんじゃない?
$ ./manage.py test [app_name ...]
settings.INSTALLED_APPS に含まれる app ディレクトリの
docstring, unittest.TestCase のサブクラス
project |---__init__.py |---app | |---__init__.py | |---models.py | |---tests.py | `---views.py |---manage.py |---settings.py |---media |---templates `---urls.py
$ ./manage.py test
Creating test database...
...
---------------------------
Ran 11 tests in 31.182s
OK
Destroying test database...
TESTの記述
Pythonインタプリタの出力を貼付けるだけ
$ ./manage.py shell [--plain]
>>> import django
>>> django.VERSION
(0, 97, 'pre')
>>> assert(django.VERSION == (0, 96, 'pre'))
...
AssertionError
# -*- coding: utf-8 -*-
"""
>>> import django
>>> django.VERSION
(0, 97, 'pre')
# 次は AssertionError になる
>>> assert(django.VERSION == (0, 96, 'pre'))
...
AssertionError
"""
>>> from django.test.client import Client
>>> c = Client()
>>> response = c.get("/")
>>> response.status_code
200
>>> "%d bytes" % len(response.content)
'8456 bytes'
>>> response.headers.get("Content-Type")
'text/html; charset=utf-8'
>>> res = c.get("/redirect"); res.status_code, res.headers["Location"]
(301, '/redirect/')
>>> res = c.post("/not.found", data=dict(form="dummy")); res.status_code, res.cookies
(404, <SimpleCookie: >)
# response.template, response.context
>>> response.content.splitlines()[0]
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
>>> response = c.get("/blog/posts.json")
>>> from django.utils import simplejson
>>> json = simplejson.read(response.content)
>>> json[0].items()
[(u'pk', u'1'), (u'model', u'blog.entry'), (u'fields', {u'content': u'\u30c6\u30b9\u30c8 ...
>>> json[0].get("fields").items()
[(u'content', u'\u30c6\u30b9\u30c8'), (u'add_date', u'2007-08-18 16:05:14'), (u'tag', [1])]
0.97-pre
>>> c.login(username="test", password="none")
False
>>> c.login(username="test", password="secret")
True
追加したり、更新したり、削除したり。
追加したり、更新したり。。。
orz
データの固まりをimportできる
JSON, XML, YAML
0.97-pre
>>> from django.core import management
>>> management.call_command("loaddata", "utils/fixtures/auth.json")
Loading 'utils/fixtures/auth' fixtures...
Installing json fixture 'utils/fixtures/auth' from absolute path.
Installed 46 object(s) from 1 fixture(s)
>>> management.call_command("flush")
Loading 'initial_data' fixtures...
No fixtures found.
0.96
>>> from django.core import management
>>> management.load_data(["helpdoc/tests/auth.json"])
Loading 'utils/fixtures/auth' fixtures...
Installing json fixture 'utils/fixtures/auth' from absolute path.
Installed 46 object(s) from 1 fixture(s)
>>> management.flush()
Loading 'initial_data' fixtures...
No fixtures found.
管理画面で作る
$ ./manage.py dumpdata app --format=json --indent=2 >app/fixtures/test.json
>>> from django.core import serializers
>>> from michilu.blog.models import Tag
>>> [(field.name, field.get_internal_type()) for field in Tag._meta.fields]
[('value', 'CharField'), ('id', 'AutoField')]
>>> tag = Tag(value="DUMMY_VALUE")
>>> template = serializers.serialize("json", queryset=[tag])
>>> template
'[{"pk": "None", "model": "blog.tag", "fields": {"value": "DUMMY_VALUE"}}]'
>>> template
'[{"pk": "None", "model": "blog.tag", "fields": {"value": "DUMMY_VALUE"}}]'
>>> template = template[1:-1].replace('"None"', '"%d"').replace('"DUMMY_VALUE"', '"%s"')
>>> template
'{"pk": "%d", "model": "blog.tag", "fields": {"value": "%s"}}'
>>> fixture = "[%s]" % (",".join([template % (i,"Spam!"*i) for i in range(1,4)]))
>>> fixture
'[{"pk": "1", "model": "blog.tag", "fields": {"value": "Spam!"}},
{"pk": "2", "model": "blog.tag", "fields": {"value": "Spam!Spam!"}},
{"pk": "3", "model": "blog.tag", "fields": {"value": "Spam!Spam!Spam!"}}]'
>>> json = simplejson.read(fixture)
>>> json[0]
{u'pk': u'1', u'model': u'blog.tag', u'fields': {u'value': u'Spam!'}}
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
lorem_ipsum.py 0.97-pre
>>> from django.contrib.webdesign import lorem_ipsum
>>> lorem_ipsum.sentence() #ramdom
u'Laudantium nihil facere, eveniet laudantium sapiente atque harum voluptatem expedita dolor unde,
provident itaque harum ipsam doloremque laudantium ex corrupti quisquam necessitatibus?'
>>> lorem_ipsum.paragraph() #between 1 and 4 sentences
u'Hic dolore voluptas ducimus magni deserunt id quo eum suscipit, ...
>>> lorem_ipsum.paragraphs(5) #paragraph lists
['Lorem ipsum dolor sit amet, consectetur adipisicing elit, ...
>>> lorem_ipsum.words(5, common=False) #ramdom words
u'dolores necessitatibus vitae aut voluptatum'
寿限無、寿限無 五劫の擦り切れ 海砂利水魚の 水行末 雲来末 風来末 食う寝る処に住む処 やぶら小路の藪柑子 パイポパイポ パイポのシューリンガン シューリンガンのグーリンダイ グーリンダイのポンポコピーのポンポコナーの 長久命の長助。
>>> from utils.contrib.webdesign import jugem
>>> print jugem.sentence()
シューリンガンのグーリンダイ magna lorem 五劫の擦り切れ dolor、
>>> print jugem.paragraph()
Magna やぶら小路の藪柑子 ut dolore incididunt 長久命の長助。, やぶら小路の藪柑子 incididunt 五劫の擦り切れ tempor ...
>>> print jugem.paragraphs(5)
[u'\u5bff\u9650\u7121\u3001\u5bff\u9650\u7121\n\u4e94\u52ab\u306e\u64e6\u308a\u5207 ...
>>> print jugem.words(5, common=False)
labore 食う寝る処に住む処 eiusmod 長久命の長助。 sed
app/tests.py
# -*- coding: utf-8 -*-
"""
... doctest here ...
"""
from django.test import TestCase
from django.test.client import Client
class SimpleTest(TestCase):
fixtures = ['mammals.json', 'birds']
def test_details(self):
response = self.client.get('/customer/details/')
self.failUnlessEqual(response.status_code, 200)
0.97-pre
$ ./manage.py test
$ ./manage.py test app
$ ./manage.py test app.SimpleTest
$ ./manage.py test app.SimpleTest.test_details
0.97-pre
assertContains(response, text, count=None, status_code=200)
assertFormError(response, form, field, errors)
assertRedirects(response, expected_path, status_code=302, target_status_code=200)
assertTemplateNotUsed(response, template_name)
assertTemplateUsed(response, template_name)
http://michilu.googlecode.com/svn/trunk/utils/doctests.py
>>> from utils.doctests import Test
>>> t = Test()
>>> response = t.client.get("/admin")
>>> t.assertRedirects(response, "/admin/", status_code=301)
>>> response = t.client.get("/admin/")
>>> t.assertContains(response, "Password")
>>> t.client.login(username="test", password="secret")
True
>>> response = t.client.get("/admin/")
>>> t.assertContains(response, "Password")
Found 0 instances of 'Password' in response (expected 1)
doctest
unittest
doctest
unittest
0.97-pre
$ ./manage.py testserver testdata.json
Creating test database...
...
Loading 'testdata' fixtures...
Installing json fixture 'testdata' from absolute path.
Installed 46 object(s) from 1 fixture(s)
Validating models...
Django version 0.97-pre, using settings 'michilu.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
^C
Server stopped.
Note that the test database, ':memory:', has not been deleted. You can explore it on your own.
