[英]How can i test a void function in python using pytest?
I just started unit testing in python using pytest. Well, when I have a function with a return value, with the "assert" I can compare a certain value with the value that the function return.我刚开始使用 pytest 在 python 中进行单元测试。好吧,当我有一个带有返回值的 function 时,通过“断言”我可以将某个值与 function 返回的值进行比较。 But if I had a void function that returns nothing and does a print at the end, for example:
但是如果我有一个 void function 什么都不返回并在最后打印,例如:
def function() -> None:
number = randint(0, 4)
if (number == 0):
print("Number 0")
elif (number == 1):
print("Number 1")
elif (number == 2):
print("Number 2")
elif (number == 3):
print("Number 3")
elif (number == 4):
print("Number 4")
How can i test this simple function to get 100% code coverage?我如何测试这个简单的 function 以获得 100% 的代码覆盖率?
One method I've found to test this function is to do a return of the value (instead of print) and print it later, and then use the assert.我发现测试这个 function 的一种方法是返回值(而不是打印)并稍后打印它,然后使用断言。 But I wanted to know if it was possible to avoid this and do a test directly on the print statemant.
但我想知道是否有可能避免这种情况并直接在打印语句上进行测试。
You can redirect sys.stdout
(the stream that print
writes to) to a buffer and then examine or assert the contents of the buffer.您可以将
sys.stdout
( print
写入的 stream)重定向到缓冲区,然后检查或断言缓冲区的内容。
>>> import io
>>> import contextlib
>>>
>>> def f():print('X')
...
>>> buf = io.StringIO()
>>> with contextlib.redirect_stdout(buf):
... f()
...
>>> print(repr(buf.getvalue()))
'X\n'
>>>
>>> buf.close()
(Recall that print() appends the value of its end
argument to the line, which defaults to '\n'
). (回想一下print()将其
end
参数的值附加到该行,默认为'\n'
)。
I suggest having a look at the plugin pytest-mock .我建议看看插件pytest-mock 。 It allows you to mock collaborating objects of your code under test.
它允许您模拟被测代码的协作对象。
Consider the following code under test:考虑以下被测代码:
# production.py
def say_hello() -> None:
print('Hello World.')
you can easily mock this now with你现在可以很容易地嘲笑这个
# production_test.py
from production import say_hello
def test_greeting(mocker):
# The "mocker" fixture is auto-magicall inserted by pytest,
# once the extenson 'pytest-mock' is installed
printer = mocker.patch('builtins.print')
say_hello()
assert printer.call_count == 1
You can also assert the arguments the printer function was called with, etc. You will find a lot of details in their useful documentation .您还可以断言 arguments 打印机 function 被调用等。您会在它们有用的文档中找到很多详细信息。
Now, consider you do not want to access the printer
, but have a code with some undesirable side-effects (eg an operation takes forever, or the result is non-predictable (random).) Let's have another example, say现在,假设您不想访问
printer
,但是有一个带有一些不良副作用的代码(例如,一个操作需要永远,或者结果是不可预测的(随机的)。)让我们再举一个例子,比如说
# deep_though.py
class DeepThought:
#: Seven and a half million years in seconds
SEVEN_HALF_MIO_YEARS = 2.366771e14
@staticmethod
def compute_answer() -> int:
time.sleep(DeepThought.SEVEN_HALF_MIO_YEARS)
return 42
yeah, I personally don't want my test suite to run 7.5 mio years.是的,我个人不希望我的测试套件运行 7.5 mio 年。 So, what do we do?
那么我们该怎么办?
# deep_thought_test.py
from deep_thought import DeepThought
def test_define_return_value(mocker) -> None:
# We use the internal python lookup path to the method
# as an identifier (from the location it is called)
mocker.patch('deep_thought.DeepThought.compute_answer', return_value=12)
assert DeepThought.compute_answer() == 12
Two more minor remarks, not directly related to the post:还有两点小意见,与帖子没有直接关系:
print
.print
是一个好习惯。 See Question 6918493 for example.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.