Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python—使具有类变量的类的单元测试独立_Python_Unit Testing_Python Unittest - Fatal编程技术网

Python—使具有类变量的类的单元测试独立

Python—使具有类变量的类的单元测试独立,python,unit-testing,python-unittest,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

我有一个带有字典的类,该字典用于缓存服务器对特定输入的响应。因为这是用于缓存的,所以它作为类变量保留

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)
在编写单元测试时,因为字典是一个类变量,所以在测试用例中缓存这些值

测试用例 如果首先执行
test\u caching
,则缓存的值将是某个模拟对象。如果首先执行
test\u do\u something
,那么调用测试用例一次的断言将失败


除了直接操作字典之外,我如何使测试彼此独立(因为这就像需要对代码的内部工作有深入了解。如果以后内部工作发生变化,该怎么办。我需要验证的只是API本身,而不是依赖内部工作)?

您需要使用Python内置的UnitTest测试用例,并实现安装和拆卸方法

如果在测试中定义
setUp()
tearDown()
,则每次调用一个测试方法时(分别在调用之前和之后)都将执行这些方法

例如:

# set up any global, consistent state here

# subclass unit test test case here.

def setUp(self):
  # prepare your state if needed for each test, if this is not considered "fiddling", use this method to set your cache to a fresh state each time
  your_cache_dict_variable = {}

### Your test methods here

def tearDown(self):
  # this will handle resetting the state, as needed

查看文档了解更多信息:

我可以建议在测试类中使用
setUp()
tearDown()
方法

from unittest import TestCase

class MyTest(TestCase):
    def setUp(self):
        self.m = MyClass()
        //anything else you need to load before testing

    def tearDown(self):
        self.m = None

    def test_caching(self):
        self.m.get_info_server('foo')
        self.m.get_info_server('foo')
        mock_client.get_from_server.assert_called_with_once('foo')

您没有明确地将其放在问题中,但我假设您的测试方法位于名为
MyClassTests
unittest.TestCase
的子类中

在测试方法中显式设置
MyClass.cache\u dict
。如果它只是一本字典,没有任何getter/setter,那么就不需要Mock


如果要保证每个测试方法都是独立的,请在
MyClassTests.setup()

中设置
MyClass.cache\u dict={}
。如果您正在对这个类进行单元测试,那么您的单元测试将需要熟悉该类的内部工作,所以只需重置缓存即可。在不调整单元测试的情况下,您几乎无法更改类的工作方式

如果您觉得这仍然会造成维护负担,则通过添加类方法使缓存处理显式化:

class MyClass:
    cache_dict = {}

    @classmethod
    def _clear_cache(cls):
        # for testing only, hook to clear the class-level cache.
        cls.cache_dict.clear()
请注意,我仍然给它起了一个带有前导下划线的名字;这不是第三方应该调用的方法,它仅用于测试。但是现在您已经集中清除了缓存,从而可以控制如何实现缓存

如果您正在使用
unittest
框架运行测试,请在中的每个测试之前清除缓存。如果您使用的是不同的测试框架,那么该框架将有一个类似的钩子。在每次测试之前清除缓存可确保始终处于干净状态


一定要考虑到缓存不是线程安全的,如果您在线程化的同时运行测试,那么这里就会出现问题。因为这也适用于缓存实现本身,所以您现在可能不担心这一点。

直接使用字典。或者将缓存支持方法添加到类中,并让这些方法处理字典。允许您的unittest了解这些知识。如果您想使其更正式,请添加一个清除缓存的classmethod。我想您的意思是在
get\u info\u server
方法中使用
self.cache\u dict
?@JacobIRR Yes
get\u info\u server
使用cache\u dict,但是测试用例不应该依赖于这条信息进行测试。如何编写没有这些的测试用例是问题本身。如果问题不够清楚,请更正。@MartijnPieters,对我有用。你能把它作为答案贴出来吗?将其标记为正确的字典。这仍然需要“摆弄”类属性dictionay。@MartijnPieters-如果需要持久化,该字典可以是全局的,如果需要刷新,则可以是临时的(在测试用例类内部)。这个解决方案允许这两种情况都起作用。我怀疑问题在于知道在哪里重置缓存。OP仍然需要重置缓存。他可以在setup或teardown方法中这样做,因为每次测试都会调用这些方法。但这就是问题的关键,是如何处理缓存之类的内部实现细节。这仍然保留了缓存。创建新实例不会清除它。
class MyClass:
    cache_dict = {}

    @classmethod
    def _clear_cache(cls):
        # for testing only, hook to clear the class-level cache.
        cls.cache_dict.clear()