2017-03-08 11 views
0

私は鼻からpytestへの一連のテストを移行しようとしていますが、私は全プロセスを検証する1つのテストの移行に問題があります。pytestとyieldベースのテスト

def is_equal(a, b): 
    assert a == b 


def inner(): 
    yield is_equal, 2, 2 
    yield is_equal, 3, 3 


def test_simple(): 
    yield is_equal, 0, 0 
    yield is_equal, 1, 1 
    for test in inner(): 
     yield test 
    yield is_equal, 4, 4 
    yield is_equal, 5, 5 


def test_complex(): 

    integers = list() 

    def update_integers(): 
     integers.extend([0, 1, 2, 3, 4, 5]) 

    yield update_integers 

    for x in integers: 
     yield is_equal, x, x 

test_simpleは鼻とpytest間の細かい動作しますが、唯一の初期update_integersテストtest_complex実行します:

~/projects/testbox$ nosetests -v 
test_nose_tests.test_simple(0, 0) ... ok 
test_nose_tests.test_simple(1, 1) ... ok 
test_nose_tests.test_simple(2, 2) ... ok 
test_nose_tests.test_simple(3, 3) ... ok 
test_nose_tests.test_simple(4, 4) ... ok 
test_nose_tests.test_simple(5, 5) ... ok 
test_nose_tests.test_complex ... ok 
test_nose_tests.test_complex(0, 0) ... ok 
test_nose_tests.test_complex(1, 1) ... ok 
test_nose_tests.test_complex(2, 2) ... ok 
test_nose_tests.test_complex(3, 3) ... ok 
test_nose_tests.test_complex(4, 4) ... ok 
test_nose_tests.test_complex(5, 5) ... ok 

---------------------------------------------------------------------- 
Ran 13 tests in 0.004s 


~/projects/testbox$ pytest -v 
====================================================================  test session starts   ===================================================================== 
platform linux2 -- Python 2.7.12, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- /usr/bin/python 
cachedir: .cache 
rootdir: /home/local/ANT/cladam/projects/testbox, inifile: 
collected 7 items 

tests/test_nose_tests.py::test_simple::[0] PASSED 
tests/test_nose_tests.py::test_simple::[1] PASSED 
tests/test_nose_tests.py::test_simple::[2] PASSED 
tests/test_nose_tests.py::test_simple::[3] PASSED 
tests/test_nose_tests.py::test_simple::[4] PASSED 
tests/test_nose_tests.py::test_simple::[5] PASSED 
tests/test_nose_tests.py::test_complex::[0] PASSED 

=================================================================== pytest-warning summary  =================================================================== 
WC1 /home/local/ANT/cladam/projects/testbox/tests/test_nose_tests.py yield tests are deprecated, and scheduled to be removed in pytest 4.0 
.... 
======================================================== 7 passed, 7  pytest-warnings in 0.01 seconds ========================================================= 

私はこのことを想定していますが

私は私の問題を表現するためにそれをダウン易しく書き直されています収集時には整数リストは空であり、これは6つの追加の収穫を集めないためです。

pytestでこのテスト構造を複製する方法はありますか? via pytest_generate_tests?

このテストは、オブジェクトを構築して操作し、プロセスの各段階でテストする一連のイベントを表しています。

  1. モデル何か
  2. 変化があるかどうかを確認するために既知の出力に対するモデル
  3. 差分に基づいてファイルを作成し、出力いくつかのモデルプロパティ
  4. を検証します。

あなたのテストの出力が示すように、事前

答えて

2

のおかげでは、利回りベースのテストが廃止されました:

WC1 /home/local/ANT/cladam/projects/testbox/tests/test_nose_tests.py yield tests are deprecated, and scheduled to be removed in pytest 4.0 

を私はあなたの代わりにpytest.parametrizeを利用するように勧め、あなたはより多くのを確認することができますここではそれについて:あなたの例からhttp://doc.pytest.org/en/latest/parametrize.html

私はテストのために、このようなものを作成します。

ここ
test_complex.py::TestComplexScenario::test_complex[0] PASSED 
test_complex.py::TestComplexScenario::test_complex[1] PASSED 
test_complex.py::TestComplexScenario::test_complex[2] PASSED 

あなたはパラメータ化に関するいくつかのより多くの例を見つけることができます:

def is_equal(a, b): 
    return a == b 


import pytest 

class TestComplexScenario: 
    @pytest.mark.parametrize("my_integer", [0, 1, 2]) 
    def test_complex(self, my_integer): 
     assert is_equal(my_integer, my_integer) 

は、ここで出力のサンプルがありhttp://layer0.authentise.com/pytest-and-parametrization.htmlあなたはまた、あなたのテスト入力用の順列を作り、ここでの例を確認することができます

:問題はpytest前にそれらのいずれかを実行するすべてのテストを収集し、そのtest_complexupdate_integers機能があるということである pytest: parameterized test with cartesian product of arguments

1

収集プロセスが終了するまで呼び出されません。

conftest.pyに次のコードを入力して、is_generatorチェックを収集ステージからテスト実行ステージに移動することでテストを実行できます。残念ながら、フックではpytest_runtest_protocolはジェネレータとして動作しないため、_pytest.main.pytest_runtestloop(pytest-3.2.1)のコンテンツ全体がコピーされ、変更されました。

import pytest 
from _pytest.compat import is_generator 
def pytest_pycollect_makeitem(collector, name, obj): 
    """ 
    Override the collector so that generators are saved as functions 
    to be run during the test phase rather than the collection phase. 
    """ 
    if collector.istestfunction(obj, name) and is_generator(obj): 
     return [pytest.Function(name, collector, args=(), callobj=obj)] 

def pytest_runtestloop(session): 
    """ 
    Copy of _pytest.main.pytest_runtestloop with the session iteration 
    modified to perform a subitem iteration. 
    """ 
    if (session.testsfailed and 
      not session.config.option.continue_on_collection_errors): 
     raise session.Interrupted(
      "%d errors during collection" % session.testsfailed) 

    if session.config.option.collectonly: 
     return True 

    for i, item in enumerate(session.items): 
     nextitem = session.items[i + 1] if i + 1 < len(session.items) else None 
     # The new functionality is here: treat all items as if they 
     # might have sub-items, and run through them one by one. 

     for subitem in get_subitems(item): 
      subitem.config.hook.pytest_runtest_protocol(item=subitem, nextitem=nextitem) 
      if getattr(session, "shouldfail", False): 
       raise session.Failed(session.shouldfail) 
      if session.shouldstop: 
       raise session.Interrupted(session.shouldstop) 
    return True 

def get_subitems(item): 
    """ 
    Return a sequence of subitems for the given item. If the item is 
    not a generator, then just yield the item itself as the sequence. 
    """ 
    if not isinstance(item, pytest.Function): 
     yield item 
    obj = item.obj 
    if is_generator(obj): 
     for number, yielded in enumerate(obj()): 
      index, call, args = interpret_yielded_test(yielded, number) 
      test = pytest.Function(item.name+index, item.parent, args=args, callobj=call) 
      yield test 
    else: 
     yield item 


def interpret_yielded_test(obj, number): 
    """ 
    Process an item yielded from a generator. If the item is named, 
    then set the index to "['name']", otherwise set it to "[number]". 
    Return the index, the callable and the arguments to the callable. 
    """ 
    if not isinstance(obj, (tuple, list)): 
     obj = (obj,) 
    if not callable(obj[0]): 
     index = "['%s']"%obj[0] 
     obj = obj[1:] 
    else: 
     index = "[%d]"%number 
    call, args = obj[0], obj[1:] 
    return index, call, args 

バージョン3.2.1以降、pytestがあまり変更されていない場合、上記は機能しません。代わりに、_pytest.main.pytest_runtestloopの最新バージョンを適切にコピーして変更してください。これは、プロジェクトが歩留まりベースのテストケースから徐々に、または少なくとも回収時に収集できる歩留まりベースのテストケースに移行する時間を提供するはずです。

関連する問題