質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3953閲覧

unittestのテスト項目の動的追加はどうやればよいでしょうか

uni8inu

総合スコア127

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

0クリップ

投稿2016/11/05 14:08

###質問
unittestのテストクラスへテスト項目を動的に追加したく思っております。
やりたいこととしては、テストクラス外のデータを元にしてテスト項目を増減させたいのです。
(こういう行為は、unittestにふさわしくない考え方かもしれないですが・・・)

簡単には、テストクラス内のメソッド
(def test_1(self),def test_2(self)....)をテスト実行時に動的に追加する、というイメージです。
こういった場合、どういった方法が取れるでしょうか?

###試したこと
手段を調べる良いキーワードが思いつかず、結局泥臭いやり方しか分かりませんでした。

  • execによる文字列からの動的な関数の生成
  • Monkey_patchによるテストクラスへのテストメソッドの注入

特にexecで文字列を関数化している部分は、もっと他にやり方あるだろ!と感じておりますが、分かりませんでした。
うまいやり方をご存じの方にご教示願いたいです。

泥臭いやり方で実装したコードはこれです。ユニットテストの実行前にテストメソッドを10個追加します。

python

1import unittest 2 3class TestMyTest(unittest.TestCase): 4 5 def setUp(self): 6 pass 7 8 def tearDown(self): 9 pass 10 11 def test_origin(self): 12 self.assertEqual("test_1","test_1") 13 14if __name__ == "__main__": 15 for i in range(10): 16 name = "test_func" + str(i) 17 18 #文字として関数定義を書き起こす / 変数から名称を作れる 19 str_for_exec = "def {0}(self): self.assertEqual('{0}','{0}')".format(name) 20 exec(str_for_exec) # 関数が定義された 21 22 #テストクラスへ注入する 23 str_monkey_patch = "TestMyTest.{0} = {1}".format(name, name) 24 exec(str_monkey_patch) 25 26 unittest.main()

泥臭いながらunittestは想定通り動き、パスしました。

text

1#実行結果 2........... 3---------------------------------------------------------------------- 4Ran 11 tests in 0.000s 5 6OK
mikkame👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

やりたいことは恐らく "データ駆動テスト" (Data-Driven Testing) が該当すると思います。

テスト内容が同じような処理であれば、テストケースを増やす必要はなく、
テストするデータのみを増やせばいいので、簡単なものであれば
繰り返し文の中で assert するだけです。

python

1 2def generateTestData(): 3 # ここで assert に渡す引数をデータ元から生成します。 4 # ジェネレータにすると便利です。 5 yield 1+1, 2, "add" 6 yield 1-1, 0, "sub" 7 yield 1*1, 1, "mul" 8 9 10for first, second, msg in generateTestData(): 11 self.assertEquals(first, second, msg)

注意点は、失敗した時にどのデータセットで失敗したのかログから分かるように、第三引数をセットします。
同じデータを元に複数のテストにかける場合は、setUp 内で生成する等、工夫してください。

動的に生成する方法は、特に exec(文字列) はお勧めしません。
エラーで行番号等を報告されても、ソースは動的に生成した文字の中、
手間がかかりデバッグが困難になります。

投稿2016/11/05 14:58

編集2016/11/05 15:07
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teamikl

2016/11/05 15:19

追記: 標準ライブラリの unittest に、動的にテスト生成を支援してくれる関数がありました。 これ読んで思いましたが、for でデータを回すだけでは不十分でしたね。 http://docs.python.jp/3/library/unittest.html#subtests > 26.4.7. サブテストを利用して繰り返しテストの区別を付ける > バージョン 3.4 で追加. > パラメータの値しか違わないような小さな差しかない複数テストを書きたい場合に、 > コンテキストマネージャ subTest() を使うことで、 > 複数の独立したテストのように扱われるテストを一つのメソッド本体内で書くことが出来ます。 ... > サブテスト無しの場合、最初の失敗で実行は停止し、i の値が表示されないためエラーの原因を突き止めるのは困難になります:
uni8inu

2016/11/05 15:52

ありがとうございます!めちゃめちゃキレイに書けました。pythonさいこうです。 ジェネレーターは殆ど使ったことなかったのですが、 テストデータのパターン入力時に、非常に強力に働きますね。これは使っていきたい技術です。 重ねて感謝したいます。
uni8inu

2016/11/05 15:55

コメントしたら、コメントが増えてました! アドバイス、感謝いたします。追記部分について、確認いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問