如何在同一测试用例中使用假设和基于 pytest-tornado 产量的测试?
How can I use hypothesis, and pytest-tornado yield-based testing, in the same test case?
我正在写 py.test tests of my code that uses the Tornado library. How can I use Hypothesis in my tests that involve coroutines and the IOLoop? I've been able to write yield-based tests without Hypothesis by using pytest-tornado 的 @pytest.mark.gen_test
,但是当我尝试将它与 @given
组合时,我收到以下错误:
FailedHealthCheck: Tests run under @given
should return None
, but test_both
returned <generator object test_both at 0x7fc4464525f0>
instead.
See http://hypothesis.readthedocs.org/en/latest/healthchecks.html for more information about this. If you want to disable just this health check, add HealthCheck.return_value
to the suppress_health_check
settings for this test.
考虑到 Hypothesis docs 说
,我非常有信心这是一个真正的问题,而不仅仅是禁用健康检查的问题
yield based tests simply won’t work.
这是演示我的情况的代码:
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_hypothesis
和 test_tornado
工作正常,但我得到 test_both
的错误,因为我同时使用 yield
和假设。
改变装饰器的顺序并没有改变任何东西,可能是因为 gen_test
装饰器只是一个属性标记。
我可以编写使用假设的基于 Tornado 的代码的测试吗?怎么样?
您可以通过在 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)
我正在写 py.test tests of my code that uses the Tornado library. How can I use Hypothesis in my tests that involve coroutines and the IOLoop? I've been able to write yield-based tests without Hypothesis by using pytest-tornado 的 @pytest.mark.gen_test
,但是当我尝试将它与 @given
组合时,我收到以下错误:
FailedHealthCheck: Tests run under
@given
should returnNone
, buttest_both
returned<generator object test_both at 0x7fc4464525f0>
instead.See http://hypothesis.readthedocs.org/en/latest/healthchecks.html for more information about this. If you want to disable just this health check, add
HealthCheck.return_value
to thesuppress_health_check
settings for this test.
考虑到 Hypothesis docs 说
,我非常有信心这是一个真正的问题,而不仅仅是禁用健康检查的问题yield based tests simply won’t work.
这是演示我的情况的代码:
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_hypothesis
和 test_tornado
工作正常,但我得到 test_both
的错误,因为我同时使用 yield
和假设。
改变装饰器的顺序并没有改变任何东西,可能是因为 gen_test
装饰器只是一个属性标记。
我可以编写使用假设的基于 Tornado 的代码的测试吗?怎么样?
您可以通过在 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)