2016-02-29 22 views
7

Sto usando pytest con selenio per automatizzare un sito web. Voglio prendere qualche schermata solo quando un caso di test fallisce. Ho già usato TestNG e con TestNG è abbastanza ad est usando l'ITestListner. Abbiamo qualcosa del genere in pytest.Come rilevare quando il test test di pytest è fallito?

Ho cercato di ottenere ciò utilizzando il metodo teardown_method() Ma questo metodo non viene eseguito quando un caso di test ha esito negativo.

import sys 

from unittestzero import Assert 
class TestPY: 
    def setup_method(self, method): 
     print("in setup method") 
     print("executing " + method.__name__) 

    def teardown_method(self, method): 
     print(".....teardown") 
     if sys.exc_info()[0]: 
      test_method_name = method 
      print test_method_name 

    def test_failtest(self): 
     Assert.fail("failed test") 

teardown_method() vengono eseguiti solo quando non ci sono fallisce

+0

controllare i ganci più piccoli: https://pytest.org/latest/example/simple.html#post-process-test-reports-failures –

+0

@KirilS. grazie per la risposta, ho provato anche quello e sembra che non funzioni. Ho il codice utente da "Creazione di informazioni sui risultati del test disponibili nelle fixture" e il mio [codegist] (https://gist.github.com/pr4bh4sh/29ca4da983d411bb2178) – pr4bh4sh

risposta

5

Secondo voi post su StackOverflow, posso condividere che è qualcosa nella mia mente, spero che vi aiuterà Wink cosa si sta cercando di fare è quello di gestire serie AssertionError eccezione che può essere generato da assert parola chiave o da qualsiasi metodo di asserzione implementato in unittest.TestCase o forse da qualsiasi metodo di asserzione personalizzato che solleva un'eccezione personalizzata. Ci sono 3 modi per farlo:

  1. Usa try-except-finally costruzione. Qualche esempio di base:

    try: 
        Assert.fail("failed test") 
    except AssertionError: 
        get_screenshot() 
        raise 
    
  2. Oppure utilizzare con dichiarazione, come contesto allenatore:

    class TestHandler: 
        def __enter__(self): 
         # maybe some set up is expected before assertion method call 
         pass 
    
        def __exit__(self, exc_type, exc_val, exc_tb): 
         # catch whether exception was raised 
         if isinstance(exc_val, AssertionError): 
          get_screenshot() 
    
    
    with TestHandler(): 
        Assert.fail("failed test") 
    

    here è possibile immergersi a profondità su come giocare con lui

  3. L'ultimo, a mio parere, è l'approccio più elegante. Utilizzando decorators. Con questo decoratore si può decorare qualsiasi metodo di prova:

    def decorator_screenshot(func): 
        def wrapper(*args, **kwargs): 
         try: 
          func(*args, **kwargs) 
         except AssertionError: 
          get_screenshot() 
          raise 
        return wrapper 
    
    
    @decorator_screenshot 
    def test_something(): 
        Assert.fail("failed test") 
    
+0

"with" sta funzionando bene fin da ora e finalmente sono in grado di fare ciò che in realtà intendevo fare. E scusa, non sono in grado di fare una sovvenzione a causa della scarsa reputazione. – pr4bh4sh

+1

Mi tufferò anche nel decoratore una volta che avrò tempo. – pr4bh4sh

+0

Felice di averlo aiutato! Non preoccuparti di upvoting, il mio tentativo è stato quello di aiutare, non di essere upvoted –

1

Questo è come lo facciamo, nota __multicall__ ha molto meno documentazione e mi ricordo di aver letto __multicall__ sta per essere deprecato, si prega di utilizzare questo con un pizzico di sale e sperimentare con la sostituzione di __multicall__ con 'elemento, chiamare' come da esempi.

def pytest_runtest_makereport(__multicall__): 
    report = __multicall__.execute() 

    if report.when == 'call': 
     xfail = hasattr(report, 'wasxfail') 
     if (report.skipped and xfail) or (report.failed and not xfail): 

      try: 
       screenshot = APP_DRIVER.take_screen_shot(format="base64") 


      except Exception as e: 
       LOG.debug("Error saving screenshot !!") 
       LOG.debug(e) 

    return report 
+2

La versione supportata di fare la stessa cosa è decorare questo con '@ pytest.hookimpl (hookwrapper = True) 'e usando' outcome = yield; report = outcome.get_result() 'invece di' __multicall__' (che attiverà un avviso di pytest dal 2.8) –

+0

__multicall__ funcarg è effettivamente deprecato. Vedi la mia risposta. – JJC

2

Dopo un po 'di lotta, alla fine questo ha lavorato per me.

In conftest.py:

@pytest.hookimpl(hookwrapper=True, tryfirst=True) 
def pytest_runtest_makereport(item, call): 
    outcome = yield 
    rep = outcome.get_result() 
    setattr(item, "rep_" + rep.when, rep) 
    return rep 

E, nel codice, in un dispositivo (ad esempio, In un dispositivo teardown per i test) usarlo in questo modo:

def tear_down(request): 
    method_name = request.node.name 
    if request.node.rep_call.failed: 
     print('test {} failed :('.format(method_name)) 
     # do more stuff like take a selenium screenshot 

nota che "richiesta" è un "funcarg" apparecchio che fornisce pytest nel contesto dei vostri test. Non devi definirlo da solo.

Fonti: pytest examples e thread on (not) making this easier.