SlideShare a Scribd company logo
WebTestでWeb APIのテスト
& Pythonメタプログラミングで
テストの自動生成
オーイシ
Shizuoka.py #6
Web APIを何故テストしたいの?
• データアーカイブを検索して再利用するためのラッパーAPI
を構築しています。
• 対象のデータベースが増える&検索対象のフィールドが増え
るとAPIが継ぎ足される感じで増えて行く。
• 仕様のアップデートで動作の影響が無いか検証する必用があ
る。
• APIが増えるとテストが大変。
WebTestとは
• WSGIアプリのテストをHTTPサーバを起動せずに行うことが
できる。※実サーバを使ったテストもできます。
• Pylons(Rails的なWebアプリケーションフレームワーク)の
パッケージの一部として開発されている。
• インストールは ”pip install WebTest” でOK
• http://docs.pylonsproject.org/projects/webtest/en/latest/
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
unittestと一緒に使うことが多いのかも
• assertEqual(a, b)
• assertTrue(x)
• assertFalse(x)
• assertGreater(a, b)
• assertIn(a, b)
• assertIs(a, b)
• assertRaises
• 等々unittestのアサートメソッドを利用します
(バージョンによって利用出来るメソッドは異なる)
実サーバのテストのサンプル
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()
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)
テストの自動生成
ドキュメントベースでWeb APIのテストを管理・実施したい。
テストの自動生成パターンを4つ見つけました
1. 動的メソッド定義
2. メタクラス
3. nose × generator
4. nose_parameterized
動的メソッド定義
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)
動的メソッド定義
1. 高階関数のtest_genは引数(a, b)を受け取りアサートメソッドを
生成し、testメソッドを返す。
2. setattr()はTestCaseに新しい属性を追加する。その属性の値がメ
ソッド名(=test_name)と関数(=test)。
3. 1-2が設定リストの要素で繰り返される。
メタクラスによる動的テスト
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)
メタクラスによる動的テスト
1. クラス定義は実はtypeのインスタンス。type(クラス名、親クラス,
メソッドや属性を定義)。
2. クラス定義にmetaclassが存在すると、クラスを生成する前に
metaclassに格納された関数がtypeの代わりに呼び出される。
3. typeは__new__メソッドでクラス生成の主な処理を行う。メタク
ラスを使うとクラス定義時に処理が実行される。
4. サンプルでは、クラス生成の前にTestSequenseMeta()が呼び出さ
れ、クラス定義が返る
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_な関数を実行してくれる。
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の引数で
テストの設定を渡す感じ?
動的メソッド定義で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
でした。
- メタプログラミングなのにアドホックすぎ!
- さすがにこのままコレがしたいわけではない。
- 設定出来る項目が多すぎるのかも。
- テストのルールを整備しかつ大量なテストであれば使
えなくは無いかも。
参考サイト
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

More Related Content

PDF
Pythonでの開発を効率的に進めるためのツール設定
PDF
131026 kansai-emacs
PDF
WordPress クエリを攻略しよう!
PDF
ExcelとPythonによる社会インフラシステムの設定ファイルの自動生成
PDF
ALPSチュートリアル(4) Python入門
PDF
8時間耐久PHPUnitの教室
PDF
Pyats Introduction
PDF
ALPSチュートリアル(5) ALPS Python入門
Pythonでの開発を効率的に進めるためのツール設定
131026 kansai-emacs
WordPress クエリを攻略しよう!
ExcelとPythonによる社会インフラシステムの設定ファイルの自動生成
ALPSチュートリアル(4) Python入門
8時間耐久PHPUnitの教室
Pyats Introduction
ALPSチュートリアル(5) ALPS Python入門

Viewers also liked (20)

PDF
Shizuoka.py #6 lt 確定申告をpythonで乗り切る
PDF
Tensor flowを使った キュウリの仕分け あれこれ
PDF
数学史 黎明期
PDF
TensorFlowによるFizz Buzz
PPTX
ClickでCLIをお手軽につくるぅぅぅ
PDF
サザエさんのじゃんけん データ分析
PPTX
第一回 機械学習
PPTX
#nds47 WebのテストをPythonでやってエビデンス取得作業から開放?
PPTX
PGXでつぶやきの類似度によるグラフを生成してみた
PPTX
For My Tay
PDF
BROOKLYN_DSM
PPT
recent advancement in contraceptives
PDF
My balsamiqproject pdf
PDF
Belgium franchise. Bebe de Paris. baby gifts
ODP
Powerpoint ingles
PPTX
Twitter retweet analysis
PDF
בניית תכנית שנתית
PPTX
Plan educativo maternidad
PDF
最近の単体テスト
PPTX
Didatica Docente - Educacion
Shizuoka.py #6 lt 確定申告をpythonで乗り切る
Tensor flowを使った キュウリの仕分け あれこれ
数学史 黎明期
TensorFlowによるFizz Buzz
ClickでCLIをお手軽につくるぅぅぅ
サザエさんのじゃんけん データ分析
第一回 機械学習
#nds47 WebのテストをPythonでやってエビデンス取得作業から開放?
PGXでつぶやきの類似度によるグラフを生成してみた
For My Tay
BROOKLYN_DSM
recent advancement in contraceptives
My balsamiqproject pdf
Belgium franchise. Bebe de Paris. baby gifts
Powerpoint ingles
Twitter retweet analysis
בניית תכנית שנתית
Plan educativo maternidad
最近の単体テスト
Didatica Docente - Educacion
Ad

Similar to Shizuoka.py #6 WebTestでWeb APIのテスト & Pythonメタプログラミングでテストの自動生成 (20)

PPTX
キーワード駆動によるシステムテストの自動化について 2015
PDF
Introduction to Continuous Test Runner MakeGood
PPTX
KEY
Sencha ug3 siesta_share
PPT
Apexコアデベロッパーセミナー(Apexコード)071010
PDF
ASP.NET シングル ページ アプリケーション (SPA) 詳説
PPT
Cubby 2006-08-23
PDF
究極のバッチフレームワーク(予定)
PPTX
Vertica 8.1.0 新機能
PDF
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
PDF
AWS Black Belt Tech シリーズ 2015 - AWS Elastic Beanstalk
PDF
Akka Unit Testing
PPTX
Vertica 7.2.3 新機能
PDF
【18-C-4】Google App Engine - 無限の彼方へ
PPTX
Geeklog2.1新機能紹介 20140723
PPTX
CLRH_120414_WFTDD
PDF
PostgreSQL 10 新機能 @オープンセミナー香川 2017
PDF
PHPUnit でテスト駆動開発を始めよう
PDF
Presto ベースのマネージドサービス Amazon Athena
PDF
Elasticsearchプラグインの作り方
キーワード駆動によるシステムテストの自動化について 2015
Introduction to Continuous Test Runner MakeGood
Sencha ug3 siesta_share
Apexコアデベロッパーセミナー(Apexコード)071010
ASP.NET シングル ページ アプリケーション (SPA) 詳説
Cubby 2006-08-23
究極のバッチフレームワーク(予定)
Vertica 8.1.0 新機能
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
AWS Black Belt Tech シリーズ 2015 - AWS Elastic Beanstalk
Akka Unit Testing
Vertica 7.2.3 新機能
【18-C-4】Google App Engine - 無限の彼方へ
Geeklog2.1新機能紹介 20140723
CLRH_120414_WFTDD
PostgreSQL 10 新機能 @オープンセミナー香川 2017
PHPUnit でテスト駆動開発を始めよう
Presto ベースのマネージドサービス Amazon Athena
Elasticsearchプラグインの作り方
Ad

More from Nao Oec (10)

PPTX
Pgx user meeting_20170602
PPTX
Lodチャレンジ2016 エリアベンチマーキング資料
PPTX
RESASを使った静岡市の新しい産業の創成手法サンプル
PPTX
Python neo4j cytoscapejsでデータ可視化入門
PDF
Dockerで作るd3.jsインタラクション共有&DL環境
PDF
Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識
PDF
コンピュータビジョン7章資料_20140830読書会
PDF
Open streetmapハンズオン@静岡まとめ
PDF
Shizuokapy 3 oec_nlp
PDF
iLeafletとは何か
Pgx user meeting_20170602
Lodチャレンジ2016 エリアベンチマーキング資料
RESASを使った静岡市の新しい産業の創成手法サンプル
Python neo4j cytoscapejsでデータ可視化入門
Dockerで作るd3.jsインタラクション共有&DL環境
Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識
コンピュータビジョン7章資料_20140830読書会
Open streetmapハンズオン@静岡まとめ
Shizuokapy 3 oec_nlp
iLeafletとは何か

Shizuoka.py #6 WebTestでWeb APIのテスト & Pythonメタプログラミングでテストの自動生成