Contenu connexe Similaire à Shizuoka.py #6 WebTestでWeb APIのテスト & Pythonメタプログラミングでテストの自動生成 (20) Shizuoka.py #6 WebTestでWeb APIのテスト & Pythonメタプログラミングでテストの自動生成4. WebTestの簡単な例
from webtest import TestApp
def application(environ, start_response):
body = 'たのしー'.encode('utf-8')
headers = [('Content-Type', 'text/html; charset=utf8'),
('Content-Length', str(len(body)))]
start_response('200 OK', headers)
return [body]
app = TestApp(application)
resp = app.get('/')
assert resp.content_type == 'text/html'
assert resp.content_length > 0
assert 'たのしー' in resp
#assert 'すごーい' in resp
# このままだと実行しても何も起きないが
# assert 'すごーい' in resp をアンコメントすると
>Traceback (most recent call last):
> File "test_webtest_basic.py", line 16, in <module>
> assert 'すごーい' in resp
>AssertionError
6. 実サーバのテストのサンプル
os.environ['WEBTEST_TARGET_URL'] = 'http://target_api_address'
app = TestApp(index)
#またはapp = TestApp('http://target_api_address')
class ApiTest(unittest.TestCase):
def test_api_root(self):
res = app.get('/')
self.assertEqual(res.status, '200 OK')
self.assertEqual(res.content_type, 'application/json')
def test_get_ids(self):
res = app.get('/bioproject?organism_name=Papilio%20xuthus')
self.assertGreater(res.json['numFound'], 1)
def test_get_metadata(self):
res = app.get('/bioproject/PRJNA25')
keys = res.json.keys()
self.assertIn("Package", keys)
def test_post_ids(self):
res = app.post_json('/bioproject', {"ids": ["PRJNA26","PRJNA25"]})
res_len = len(list(res.json))
self.assertEqual(res_len, 2)
if __name__ == '__main__':
unittest.main()
7. WebTest +unittestの結果
#このままテストがエラーを発生せず完了すると
Ran 4 tests in 0.898s
OK
# エラーを発生するよう、テストを変更すると…
def test_post_ids(self):
res = app.post_json('/bioproject', {"ids": ["PRJNA26", "PRJNA25"]})
res_len = len(list(res.json))
self.assertEqual(res_len, 3)
F
==================================================================
FAIL: test_post_ids (__main__.ApiTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_api.py", line 27, in test_post_ids
self.assertEqual(res_len, 3)
AssertionError: 2 != 3
----------------------------------------------------------------------
Ran 4 tests in 0.575s
FAILED (failures=1)
11. 動的メソッド定義
import unittest
l = [["foo", "a", "a"], ["bar", "a", "b"], ["baz", "b", "b"]]
class TestSequense(unittest.TestCase):
pass
def test_gen(a, b):
def test(self):
self.assertEqual(a, b)
return test
if __name__ == '__main__':
for t in l:
test_name = 'test_%s' % t[0]
test = test_gen(t[1], t[2])
setattr(TestSequense, test_name, test)
unittest.main()
F..
======================================================================
FAIL: test_bar (__main__.TestSequense)
~
Ran 3 tests in 0.001s
FAILED (failures=1)
13. メタクラスによる動的テスト
import unittest
l = [["foo", "a", "b"], ["bar", "a", "b"], ["baz", "a", "a"]]
class TestSequenseMeta(type):
def __new__(mcs, cls_name, cls_base, cls_dict):
def gen_test(a, b):
def test(self):
self.assertEqual(a, b)
return test
for tname, a, b in l:
test_name = "test_{}".format(tname)
cls_dict[test_name] = gen_test(a, b)
return type.__new__(mcs, cls_name, cls_base, cls_dict)
class TestSequence(unittest.TestCase, metaclass=TestSequenseMeta):
pass
if __name__ == '__main__':
unittest.main()
F..
======================================================================
~
Ran 3 tests in 0.001s
FAILED (failures=1)
15. nose × generator
param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')]
def test_generator():
for params in param_list:
yield check_em, params[0], params[1]
def check_em(a, b):
assert a == b
$ nosetests test_nose_generators.py
.F.
======================================================================
~
File "/Users/../test_nose_generators.py", line 11, in check_em
assert a == b
AssertionError
----------------------------------------------------------------------
Ran 3 tests in 0.002s
FAILED (failures=1)
nosetestsコマンドでtest_xx.pyなファイルを探し
てtest_な関数を実行してくれる。
16. nose_parameterized
from nose_parameterized import parameterized
import unittest
class TestSequence(unittest.TestCase):
@parameterized.expand(
[
["foo", "a", "b"],
["bar", "b", "b"],
["baz", "a", "a"],
])
def test_sequence(self, name, a, b):
self.assertEqual(a,b)
if __name__ == '__main__':
unittest.main()
FAIL: test_sequence_1_bar (__main__.TestSequence)
----------------------------------------------------------------------
~
File "test_nose_parameterized.py", line 13, in test_sequence
self.assertEqual(a,b)
AssertionError: 'a' != 'b'
- a
+ b
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1)
decoratorの引数で
テストの設定を渡す感じ?
17. 動的メソッド定義でWebTestしてみた
import unittest
from webtest import TestApp
app = TestApp('http://target_api_url')
tests = [["bioproject", "/bioproject/PRJNA25", "In", "Package"],
["organism_name", "/bioproject?organism_name=Papilio%20xuthus", "Greater", 1],
["root", "/sra", "Equal", "200 OK”]]
class TestSequense(unittest.TestCase):
pass
def test_gen(path, method, b):
def Equal(self):
res = app.get(path)
a = res.status
self.assertEqual(a, b)
def Greater(self):
res = app.get(path)
a = res.json['numFound']
self.assertGreater(a, b)
def In(self):
res = app.get(path)
a = res.json.keys()
self.assertIn(b, a)
#return eval(method)
return locals()[method]
if __name__ == '__main__':
for name, path, method, val in tests:
test_name = 'test_{}'.format(name)
test = test_gen(path, method, val)
setattr(TestSequense, test_name, test)
-------------------------------------------------------
Ran 3 tests in 0.298s
OK
でした。
19. 参考サイト
How to generate dynamic (parametrized) unit tests in python?
http://stackoverflow.com/questions/32899/how-to-generate-dynamic-parametrized-unit-tests-in-python
メタプログラミングPython
https://tell-k.github.io/pyconjp2016/#1
Pythonによる黒魔術入門
http://www.slideshare.net/ssuser38b704/ll-lang-blackmagic
Pythonでメタプログラミング
http://qiita.com/fujimisakari/items/0d4786dd9ddeed4eb702