如何在同一测试用例中使用假设和基于pytest-tornado yield的测试?

时间:2016-05-15 18:21:36

标签: python python-2.7 tornado pytest python-hypothesis

我正在编写使用py.test库的代码的Tornado测试。如何在涉及协同程序和IOLoop的测试中使用Hypothesis?我已经能够使用pytest-tornado @pytest.mark.gen_test编写没有假设的基于收益率的测试,但当我尝试将其与@given结合使用时,我收到了以下错误:

  

FailedHealthCheck:在@given下运行的测试应该返回None,但test_both会返回<generator object test_both at 0x7fc4464525f0>

     

有关详细信息,请参阅http://hypothesis.readthedocs.org/en/latest/healthchecks.html。如果您只想禁用此运行状况检查,请将HealthCheck.return_value添加到此测试的suppress_health_check设置中。

我非常确信这是一个真正的问题而不只是一个禁用健康检查的问题,考虑到Hypothesis docs

  

基于产量的测试根本不起作用。

以下代码演示了我的情况:

class MyHandler(RequestHandler):

    @gen.coroutine
    def get(self, x):
        yield gen.moment
        self.write(str(int(x) + 1))
        self.finish()


@pytest.fixture
def app():
    return Application([(r'/([0-9]+)', MyHandler)])


@given(x=strategies.integers(min_value=0))
def test_hypothesis(x):
    assert int(str(x)) == x


@pytest.mark.gen_test
def test_tornado(app, http_client, base_url):
    x = 123
    response = yield http_client.fetch('%s/%i' % (base_url, x))
    assert int(response.body) == x + 1


@pytest.mark.gen_test
@given(x=strategies.integers(min_value=0))
def test_both(x, app, http_client, base_url):
    response = yield http_client.fetch('%s/%i' % (base_url, x))
    assert int(response.body) == x + 1

test_hypothesistest_tornado工作正常,但我收到test_both的错误,因为我一起使用yield和假设。

更改装饰器的顺序并没有改变任何东西,可能是因为gen_test装饰器只是一个属性标记。

我可以编写使用假设的基于Tornado的代码的测试吗?怎么样?

1 个答案:

答案 0 :(得分:7)

您可以通过调用pytest-tornado的io_loop py.test夹具上的run_sync()来完成此操作。这可以用来代替yield

@given(x=strategies.integers(min_value=0))
def test_solution(x, app, http_client, base_url, io_loop):
    response = io_loop.run_sync(
        lambda: http_client.fetch('%s/%i' % (base_url, x)))
    assert int(response.body) == x + 1

或者您可以将测试的正文放在协程中,以便它可以继续使用yield,并使用run_sync()调用此协程:

@given(x=strategies.integers(min_value=0))
def test_solution_general(x, app, http_client, base_url, io_loop):
    @gen.coroutine
    def test_gen():
        response = yield http_client.fetch('%s/%i' % (base_url, x))
        assert int(response.body) == x + 1
    io_loop.run_sync(test_gen)