2011-02-07 7 views
15

質問まず、あなたが興味があれば質問してください。pythonでpy.testテストを生成する

py.testのコンテキストでは、小さなテスト関数テンプレートセットから大きなテスト関数セットを生成するにはどうすればよいですか?

のような何か:

models = [model1,model2,model3] 
data_sets = [data1,data2,data3] 

def generate_test_learn_parameter_function(model,data): 
    def this_test(model,data): 
     param = model.learn_parameters(data) 
     assert((param - model.param) < 0.1) 
    return this_test 

for model,data in zip(models,data_sets): 
    # how can py.test can see the results of this function? 
    generate_test_learn_parameter_function(model,data) 

説明:

私はユニットテストに入るために努力しています。私は「科学」のためのコードを書いています。私は、数学的には複雑ですが、プログラミングの観点からはそれほど悪くないと思うコードを書いています。私が「科学」から来たのは、私が単体テストにはまったく新しいことですが、私のCS仲間にはそれが「行うべきこと」であると確信していました。

私が書いているコードは、モデル構造といくつかのデータをとり、モデルのパラメータを学習します。私の単体テストは、一連のモデル構造とあらかじめ生成されたデータセットで構成され、各構造+データに対して約5回の機械学習タスクが完了します。

私はこのコードを手渡しても、タスクごとにモデルごとに1つのテストが必要です。新しいモデルが登場するたびに、5つのタスクをコピーして貼り付け、どのピクルス構造+データを変更する必要があります。これは私にとって悪い習慣のように感じます。理想的には、5つの各タスクを定義し、次に指定した構造のリストのテスト関数を吐き出す5つのテンプレート関数です。

グーグルでは、どちらも私の脳を刺激し、より簡単な方法が必要であることを示唆しています。この問題は適切なプログラマーが定期的に直面しなければならないためです。そこにはありますか?


編集:この問題を解決する方法は次のとおりです。

def pytest_generate_tests(metafunc): 
    if "model" in metafunc.funcargnames: 
     models = [model1,model2,model3] 
     for model in models: 
      metafunc.addcall(funcargs=dict(model=model)) 

def test_awesome(model): 
    assert model == "awesome" 

これは、私のモデルリストの各モデルにtest_awesomeテストを適用します!ありがとう@dfichter!

(注:常にところで、合格主張)

+0

一般的にはそのような動的テストコードを生成するために悪い考えです。そのため、テストコードなどのテストを書く必要があります。 '5つのタスクをコピーして貼り付けます.'これは、新しいコードやコピー貼りを生成する代わりに、関数が何を正確に知らなくてもテストできる共通点を見つけることができると思います再テスト。 – Falmarri

+2

現時点では、私はdef test_learnのようなテストを書いています:モデルのモデルのために:assert(error

+1

@Falmarri:http://en.wikipedia.org/wiki/Copy_and_paste_programmingほとんどすべての費用でそれを避けてください。 – lpapp

答えて

15

良いの本能。 py.testは、pytest_generate_tests()フックで話している内容を正確にサポートしています。彼らはそれを説明しますhere

+0

これは素晴らしいです。私は私の質問を編集して、最後に何をしたのかを覚えておいてください。誰かが似たようなことを探しているのであれば。 –

+0

dfichter、OPにインラインでの例を与えることはできますか? – lpapp

+0

これは壊れたリンクになりました –

4

parametrized fixturesを使用することもできます。フックはPy.test用のプラグインを構築するためのAPIですが、パラメータ化されたフィクスチャは、複数の値を出力し、追加のテストケースを生成するフィクスチャを作成する一般的な方法です。

プラグインは、テストケース固有の機能ではなく、プロジェクト全体(またはパッケージ全体)の機能を意図しており、パラメータ化されたフィクスチャは、テストケースのために一部のリソースをパラメータ化するために必要なものです。

だからあなたのソリューションは、そのように書き換えることができます

@pytest.fixture(params=[model1, model2, model3]) 
def model(request): 
    return request.param 

def test_awesome(model): 
    assert model == "awesome"