2017-08-02 1 views
1

J'ai une fonction que j'écris des tests unitaires pour utiliser pytest. Le seul problème est que puisque j'écris plusieurs tests pour la même fonction, quelques tests échouent à cause du décorateur cachetools.ttl_cache. Ce décorateur rend la fonction retourne la même valeur chaque fois qu'elle est en cours d'exécution ce qui gâche les tests. Ce décorateur n'est pas présent dans la fonction que je suis en train de tester mais dans une fonction appelée par celui que je suis en train de tester. Je ne peux pas enlever ce décorateur de la fonction que je suis en train de tester. Voici le test:Le test de l'unité de Pytest échoue car la fonction de la cible a le cachetools.ttl_cache decorator

@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 

Et voici la fonction à tester:

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)) 

Obtenez la fonction Split Test:

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

Comment puis-je faire si ce décorateur de cache est ignoré? Toute aide est grandement appréciée

+0

Je pense que vous devez patcher 'cachetools' avant d'exécuter des tests et remplacer' ttl_cache' par une fonction qui ne cache rien. – phd

Répondre

1

Je suggère de vider le cache de la fonction après chaque test.

Le cachetools documentation ne mentionne pas cela, mais de the source code il semble que les décorateurs de cache exposent une fonction cache_clear.

Pour votre exemple de code en cours de test:

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()) 

Ce serait mon approche (suppose pytest> = 3, sinon utilisez le décorateur yield_fixture):

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

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

Ce clear_cache appareil utilise un rendement appareil qui est automatiquement utilisé après chaque test (autouse=True) pour effectuer le nettoyage après chaque test. Vous pouvez également utiliser the request fixture and request.addfinalizer pour exécuter une fonction de nettoyage.

+0

Merci pour votre suggestion, mais je reçois cette erreur lorsque j'exécute ce projecteur ci-dessus: 'AttributeError: l'objet 'function' n'a pas d'attribut 'clear_cache'' Existe-t-il un autre moyen de vider le cache? –

+0

Oups, je l'ai inversé, c'est 'cache_clear()'. Je vais mettre à jour ma réponse. BTW sauf si vous exécutez une version différente de cachetools, votre exemple devrait afficher 'cachetools.func.ttl_cache' comme décorateur. J'ai testé la version 2.0.0 de cachetools –

+0

Vous avez frappé le clou sur la tête. Merci beaucoup –