为什么从生成器中调用模拟对象无法正确测试?
Why does a call to a mocked object from within a generator fail to test correctly?
在下面的测试代码中,生成器 class 包含两个方法,每个方法调用计数器 class 的 next_count
方法。
这两个对 next_count
的调用使用 assert_called_with
通过两个几乎相同的测试进行了测试。生成器方法的测试失败。为什么?如何测试此调用?
正在测试的代码
generator.py
class Counter:
def __init__(self):
self.count = 1
def next_count(self):
self.count += 1
return self.count
class Generator:
def __init__(self):
self.counter = Counter()
def direct_call(self):
self.counter.next_count()
def iter_event(self):
while True:
yield self.counter.count
self.counter.next_count()
测试模块
test_generator.py
import unittest
import unittest.mock
import generator
class Generator(unittest.TestCase):
def setUp(self):
p = unittest.mock.patch('generator.Counter')
self.addCleanup(p.stop)
self.mock_counter = p.start()
def test_next_count_called_in_direct_call(self): # Passes
g = generator.Generator()
g.direct_call()
self.mock_counter.assert_called_with()
def test_next_count_called_in_iter_event(self): # Fails
g = generator.Generator()
count_gen = g.iter_event()
next(count_gen)
next(count_gen)
self.mock_counter.next_count.assert_called_with()
这与发电机无关。您测试了 2 个不同的东西,并且在两个测试中都测试了错误的东西。
你的两个测试测试了不同的东西:
def test_next_count_called_in_direct_call(self): # Passes
# ...
self.mock_counter.assert_called_with()
这测试是否调用了 class。它确实被称为Counter()
。请记住,mock_counter
嘲笑了 class,而不是实例。
def test_next_count_called_in_iter_event(self): # Fails
# ...
self.mock_counter.next_count.assert_called_with()
这将测试是否调用了属性 Counter.next_count
。这从未被调用,因为它是在实例上调用的。
正确的测试是查看实例 上的 属性是否被调用:
self.mock_counter.return_value.next_count.assert_called_with()
或
self.mock_counter().next_count.assert_called_with()
使用这个是两个测试。
因为 mock_counter
是 class,它可能更适合命名为 MockCounter
.
以后,打印出你的 mock 的 mock_calls
attribute;它会显示 was 调用的内容。对于这两个测试,此打印:
[call(), call().next_count()]
在下面的测试代码中,生成器 class 包含两个方法,每个方法调用计数器 class 的 next_count
方法。
这两个对 next_count
的调用使用 assert_called_with
通过两个几乎相同的测试进行了测试。生成器方法的测试失败。为什么?如何测试此调用?
正在测试的代码
generator.py
class Counter:
def __init__(self):
self.count = 1
def next_count(self):
self.count += 1
return self.count
class Generator:
def __init__(self):
self.counter = Counter()
def direct_call(self):
self.counter.next_count()
def iter_event(self):
while True:
yield self.counter.count
self.counter.next_count()
测试模块
test_generator.py
import unittest
import unittest.mock
import generator
class Generator(unittest.TestCase):
def setUp(self):
p = unittest.mock.patch('generator.Counter')
self.addCleanup(p.stop)
self.mock_counter = p.start()
def test_next_count_called_in_direct_call(self): # Passes
g = generator.Generator()
g.direct_call()
self.mock_counter.assert_called_with()
def test_next_count_called_in_iter_event(self): # Fails
g = generator.Generator()
count_gen = g.iter_event()
next(count_gen)
next(count_gen)
self.mock_counter.next_count.assert_called_with()
这与发电机无关。您测试了 2 个不同的东西,并且在两个测试中都测试了错误的东西。
你的两个测试测试了不同的东西:
def test_next_count_called_in_direct_call(self): # Passes
# ...
self.mock_counter.assert_called_with()
这测试是否调用了 class。它确实被称为Counter()
。请记住,mock_counter
嘲笑了 class,而不是实例。
def test_next_count_called_in_iter_event(self): # Fails
# ...
self.mock_counter.next_count.assert_called_with()
这将测试是否调用了属性 Counter.next_count
。这从未被调用,因为它是在实例上调用的。
正确的测试是查看实例 上的 属性是否被调用:
self.mock_counter.return_value.next_count.assert_called_with()
或
self.mock_counter().next_count.assert_called_with()
使用这个是两个测试。
因为 mock_counter
是 class,它可能更适合命名为 MockCounter
.
以后,打印出你的 mock 的 mock_calls
attribute;它会显示 was 调用的内容。对于这两个测试,此打印:
[call(), call().next_count()]