假设我有一个单元测试,它模拟一些类
A
以返回自定义值。我希望能够更改模拟
A
实例返回的值,但我绝对不想意外更改返回值的类型并导致我的测试无意中检查错误的内容。
例如,采用下面的代码:
import datetime
import unittest
import unittest.mock
class A:
def foo(self, getter):
return getter.get_time() == '2020-01-01'
class Getter:
def get_time(self) -> datetime.datetime:
return datetime.datetime(2020,1,1)
@unittest.mock.patch("__main__.Getter", autospec=True)
class MyTestCase(unittest.TestCase):
def test_case_1(self, Getter):
getter = Getter()
getter.get_time.return_value = '2020-01-01'
a = A()
self.assertTrue(a.foo(getter))
test_case = MyTestCase()
test_case.test_case_1()
在上面的单元测试中,我们应该检查时间是否匹配“2020-01-01”,但是我们将
return_value
of
get_time
设置为一个字符串,因此,即使违反了
get_time
(返回a
datetime
)的返回类型提示,测试也会成功,因此实际代码永远无法工作。有没有办法让unittest/mock 找到这个并告诉我我错误地设置了
return_type
一个与方法上的类型提示不兼容的值?
Python 中的 unittest.mock 库本身没有内建的方法来强制执行返回值类型提示。 然而,你可以结合使用其它工具来达到目的。
1. 使用类型检查器,比如 MyPy:
MyPy 可以分析你的代码,包括单元测试,并验证类型提示是否被遵守。如果你设置一个返回值与被模拟方法的类型提示不符,MyPy 将会报告一个错误。
-
安装 MyPy:
bash pip install mypy
-
运行 MyPy:
bash mypy your_module.py
在你的例子中,MyPy 会将
getter.get_time.return_value = '2020-01-01'
标记为错误,因为它违反了
get_time
的返回值类型提示 (
datetime.datetime
)。
2. 使用模拟库,支持类型检查,比如 pytest-mock:
pytest-mock 是一个 pytest 插件,它提供了增强的模拟功能,包括对类型提示的基本支持。当与类型检查器(如 MyPy)一起使用时,它可以帮助识别模拟返回值类型的不匹配。
-
安装 pytest-mock:
bash pip install pytest-mock
-
例子:
```python import datetime import pytest
class A: def foo(self, getter): return getter.get_time() == '2020-01-01'
class Getter: def get_time(self) -> datetime.datetime: return datetime.datetime(2020,1,1)
@pytest.mark.parametrize("mock_return_value", [ datetime.datetime(2020, 1, 1), # 正确的类型 '2020-01-01' # 错误的类型 ]) def test_case_1(self, mocker, mock_return_value): mocker.patch(" main .Getter.get_time", return_value=mock_return_value) a = A() assert a.foo(Getter()) ```
在这个例子中,我们使用 pytest-mock 来修补
Getter.get_time
方法,并使用参数化测试来测试不同的返回值,包括正确和错误的类型。MyPy 会将错误类型的返回值标记为错误。
通过结合使用类型检查器和像 pytest-mock 这样的库,你可以在编写单元测试时获得更好的类型安全性,并尽早捕获潜在的错误。
标签:python,unit-testing,python-typing From: 69029431