模拟返回对象的函数会导致断言错误:预期'...'被调用过一次。调用 0 次



我正在写一个简单的例子来帮助我理解mocking在unittest中是如何工作的。我有一个具有两个功能的模块:

# model.animals.py
def get_animals(animal_type):
db = connect_to_db()
result = db.query_all_data()
return list(filter(lambda x: x['animal_type'] == animal_type, result))
def connect_to_db():
pass # That would normally return a DB connection instance

我想测试get_animals((函数,它使用DB连接来检索所有动物的信息,然后根据动物类型过滤返回的数据。由于我不想设置整个数据库,所以我只想模拟返回数据库连接实例的connect_to_db((函数。

这是我的测试课:

# test_mock.py
from unittest import TestCase, main
from unittest.mock import Mock, patch
from model.animals import get_animals

class GetDataTest(TestCase):
@patch('model.animals.connect_to_db')
def test_get_animals(self, mock_db: Mock):
mock_db.return_value.query_all_data.return_value = [
{
'animal_type': 'meerkat',
'age': 5
},
{
'animal_type': 'meerkat',
'age': 11
},
{
'animal_type': 'cow',
'age': 3
}
]
result = get_animals('meerkat') # Run the function under test
mock_db.assert_called_once() # OK
mock_db.query_all_data.assert_called_once() # AssertionError
self.assertEqual(len(result), 2) # OK
self.assertEqual(result[0]['age'], 5) # OK
if __name__ == "__main__":
main()

作为测试的一部分,我不仅想根据动物的类型检查对它们的过滤,还想检查是否调用了get_animals((中的所有方法。

测试通常按预期进行,但在检查query_all_data((函数是否已调用时出错:

AssertionError: Expected 'query_all_data' to have been called once. Called 0 times.

当我将spec=True添加到我的补丁时,我会得到另一个错误:

AttributeError: Mock object has no attribute 'query_all_data'

很明显,函数query_all_data在mock中不可见,即使我在使用mock_db.return_value.query_all_data.return_value = ...的测试中设置了它的返回值。

我错过了什么?

mock_db.query_all_data.assert_called_once()失败的原因是它应该是mock_db.return_value.query_all_data.assert_called_once()

我创建了一个助手库来帮助我为mock生成断言,这样我就不会经常遇到这样的问题。

使用方法:pip install mock-generator

然后,在您的测试中,将这些行放在result = get_animals('meerkat'):之后

from mock_autogen import generate_asserts
generate_asserts(mock_db)

当你运行测试时,它会为你生成断言(打印到控制台并复制到剪贴板(:

assert 1 == mock_db.call_count
mock_db.assert_called_once_with()
mock_db.return_value.query_all_data.assert_called_once_with()

然后,您可以编辑生成的断言,并使用适合您测试的断言。

最新更新