Pytest单元测试失败,因为目标函数有cachetools.ttl_cache装饰器

时间:2017-08-02 10:45:22

标签: python unit-testing mocking pytest

我有一个函数,我正在编写使用pytest的单元测试。唯一的问题是,因为我正在为同一个函数编写多个测试,所以由于cachetools.ttl_cache装饰器,一些测试失败了。这个装饰器使函数每次运行时返回相同的值,这会使测试变得混乱。这个装饰器不存在于我正在测试的函数中,而是存在于我正在测试的函数中调用的函数中。我无法从我正在测试的函数中删除此装饰器。这是测试:

@patch('load_balancer.model_helpers.DBSession')
def test_returns_true_if_split_test_is_external(self, dbsession, group_ctx):
    group_ctx.group_id = '{}-{}'.format('2222222222', '123456789')
    split_test = Mock()
    split_test.state = 'external'
    config = {
        'query.return_value.filter.return_value.first.return_value': split_test
    }
    dbsession.configure_mock(**config)
    assert group_ctx.is_in_variation_group('foo') == True

以下是要测试的功能:

def is_in_variation_group(self, split_test=None):
    try:
        split_test = get_split_test(split_test) # This function has the 
        #decorator
        log.info('Split test {} is set to {}'.format(split_test.name,
                                                     split_test.state))
        if not split_test or split_test.state == 'off':
            return False

        phone_number = int(self.group_id.split('-')[0])
        if split_test.state == 'internal':
            return True if str(phone_number) in INTERNAL_GUINEA_PIGS else False
        if split_test.state == 'external':
            return True if phone_number % 2 == 0 else False
    except Exception as e:
        log.warning("A {} occurred while evaluating membership into {}'s variation "
                    "group".format(e.__class__.__name__, split_test))

获取拆分测试功能:

    @cachetools.ttl_cache(maxsize=1024, ttl=60)
    def get_split_test(name):
         return (DBSession.query(SplitTest)
                 .filter(SplitTest.name == name)
                 .first())

我怎样才能使这个缓存装饰器被忽略?非常感谢任何帮助

1 个答案:

答案 0 :(得分:4)

我建议在每次测试运行后清除函数的缓存。

cachetools documentation没有提到这一点,但是从the source code开始,缓存装饰器会显示cache_clear函数。

对于您测试的示例代码:

import cachetools.func

@cachetools.func.ttl_cache(maxsize=1024, ttl=60)
def get_split_test(name):
     return (DBSession.query(SplitTest)
             .filter(SplitTest.name == name)
             .first())

这将是我的方法(假设pytest> = 3,否则使用yield_fixture装饰器):

@pytest.fixture(autouse=True)
def clear_cache():
    yield
    get_split_test.cache_clear()

def test_foo():
    pass # Test your function like normal.

clear_cache fixture使用每次测试后自动使用的yield夹具(autouse=True)在每次测试后执行清理。您还可以使用the request fixture and request.addfinalizer运行清理功能。