Ken*_*chi 5 python unit-testing python-unittest
我有一个带有字典的类,用于缓存来自服务器的特定输入响应.由于这用于缓存目的,因此将其保存为类变量.
class MyClass:
cache_dict = {}
def get_info_server(self, arg):
if arg not in self.cache_dict:
self.cache_dict[arg] = Client.get_from_server(arg)
return cache_dict[arg]
def do_something(self, arg):
# Do something based on get_info_server(arg)
Run Code Online (Sandbox Code Playgroud)
在编写单元测试时,由于字典是一个类变量,因此值跨越测试用例进行缓存.
# Assume that Client is mocked.
def test_caching():
m = MyClass()
m.get_info_server('foo')
m.get_info_server('foo')
mock_client.get_from_server.assert_called_with_once('foo')
def test_do_something():
m = MyClass()
mock_client.get_from_server.return_value = 'bar'
m.do_something('foo') # This internally calls get_info_server('foo')
Run Code Online (Sandbox Code Playgroud)
如果test_caching先执行,则缓存的值将是一些模拟对象.如果test_do_something先执行,那么测试用例只被调用一次的断言将失败.
除了直接操作字典之外,我如何使测试彼此独立(因为这需要深入了解代码的内部工作.如果内部工作稍后要改变,那么我需要验证的是API.本身,而不是依靠内部工作)?
您确实无法避免在这里重置缓存。如果您正在对此类进行单元测试,那么您的单元测试将需要对该类的内部工作原理有深入的了解,因此只需重置缓存即可。无论如何,你很少可以在不调整单元测试的情况下改变类的工作方式。
如果您觉得这仍然会造成维护负担,那么可以通过添加类方法来明确缓存处理:
class MyClass:
cache_dict = {}
@classmethod
def _clear_cache(cls):
# for testing only, hook to clear the class-level cache.
cls.cache_dict.clear()
Run Code Online (Sandbox Code Playgroud)
请注意,我仍然给它起了一个带有前导下划线的名称;这不是第三方应该调用的方法,它仅用于测试。但现在您可以集中清除缓存,从而可以控制它的实现方式。
如果您使用框架来运行测试,请在方法unittest中的每个测试之前清除缓存。如果您使用不同的测试框架,该框架将具有类似的钩子。在每次测试之前清除缓存可确保您始终保持干净的状态。TestCase.setUp()
请考虑到您的缓存不是线程安全的,如果您与线程并行运行测试,则会出现问题。由于这也适用于缓存实现本身,因此您现在可能不需要担心这一点。
| 归档时间: |
|
| 查看次数: |
947 次 |
| 最近记录: |