2012-09-19 9 views
20

Chciałbym, aby mój moduł unittest Pythona powiedział biegaczowi testowemu, aby w pewnych sytuacjach pominął jego całość (np. Nie można zaimportować modułu lub zlokalizować krytycznego zasobu).Jak mogę pominąć cały moduł Unittest Python w czasie wykonywania?

Mogę użyć @unittest.skipIf(...), aby pominąć klasę unittest.TestCase, ale jak mogę pominąć cały moduł cały moduł? Stosowanie pominięć do każdej klasy nie jest wystarczające, ponieważ same definicje klas mogą powodować wyjątki, jeśli moduł nie zostanie zaimportowany.

+2

FYI, jest blog na ten temat na http://colinnewell.wordpress.com/2012/08/31/skippng-python-unit-tests-if-a-dependency-is-missing/ –

+1

@Mu Mind, działa to tylko z tym, że mówię "nosem", aby "szybko zawieść". Wywołanie metody 'unittest.SkipTest()' wydaje się być liczone jako niepowodzenie i zatrzymuje wykonywanie. –

Odpowiedz

6

Po patrząc na drugim answe rs tutaj, to jest najlepsza odpowiedź, którą wymyśliłem. To brzydkie, osadzanie całego zestawu testów w obsłudze wyjątków, ale wydaje się, że robi to, co chcesz. W szczególności pomijanie testów, gdy import nie działa.

Zakładając, że mówisz o używaniu nosetests-x do przeprowadzania testów, to powinieneś przejść obok testów, które pomijają, przynajmniej pojawiły się, gdy próbowałem.

import unittest 
try: 
    import PyQt4 
    # the rest of the imports 


    # actual tests go here. 
    class TestDataEntryMixin(unittest.TestCase): 
     def test_somefeature(self): 
      # .... 

except ImportError, e: 
    if e.message.find('PyQt4') >= 0: 
     class TestMissingDependency(unittest.TestCase): 

      @unittest.skip('Missing dependency - ' + e.message) 
      def test_fail(): 
       pass 
    else: 
     raise 

if __name__ == '__main__': 
    unittest.main() 

Jeśli import nie powiedzie się, zastępuje testowy test pojedynczym testem, który po prostu pomija. Próbowałem też upewnić się, że przypadkowo nie połknie żadnych wyjątków. To rozwiązanie wiele zawdzięcza wszystkim innym odpowiedziom i komentarzom na pytanie.

Jeśli uruchomić go w trybie opisowym widać to, gdy pomija,

test_fail (test_openihm_gui_interface_mixins.TestMissingDependency) ... skipped 'Missing dependency - No module named PyQt4' 
+0

Myślę, że to najlepsza odpowiedź, ale masz rację, jest brzydka. :-) –

+0

Pierwsze "DeprecationWarning: BaseException.message jest przestarzałe od Python 2.6? Musisz to zrobić: http://stackoverflow.com/questions/1272138/baseexception-message-deprecated-in-python-2-6 – crazysim

2

Może być brudny umieścić wszystkie definicje podklasy unittest.TestCase w try...except bloku ale to działa:

import unittest 
try: 
    import eggs 
    class Spam(unittest.TestCase): 
     pass 
    class Ham(unittest.TestCase): 
     pass 
    # ... 
except ImportError: 
    # print 'could not import eggs' 
    pass 

Żaden z podklasy byłyby zdefiniowane, jeżeli import eggs nie powiedzie się i tych wszystkich, Klasy() zostaną pominięte. Nie ma odzwierciedlenia w wynikach (dobrych lub złych w zależności od tego, co chcesz).

+0

Brudne rozwiązanie wymyślonego problemu nie jest takie złe;) –

+1

@Mu Mind, czy to naprawdę wymyślone? Mój przypadek użycia uruchamia pakiet testowy na wielu platformach (niektóre z nich mogą nie być w stanie "importować jajek"). –

+0

Przeważnie dawałem ci trudność. Wydaje mi się, że nieco o błędach definicji klas brzmi trochę dziwnie, ale wyłączenie "tego modułu" wydaje się czystsze niż wyłączenie "wszystkich klas w tym module". –

12

Jeśli przyjrzeć się definicji unittest.skipIf i unittest.skip, można zauważyć, że klucz wykonuje raise unittest.SkipTest(reason) podczas wykonywania testu. Jeśli jesteś w porządku z konieczności to pokazać się jako jeden pomijane testu zamiast kilku w TestRunner, można po prostu podnieść unittest.SkipTest się na imporcie:

import unittest 
try: 
    # do thing 
except SomeException: 
    raise unittest.SkipTest("Such-and-such failed. Skipping all tests in foo.py") 

Biegając z nosetests -v daje:

Failure: SkipTest (Such-and-such failed. Skipping all tests in foo.py) ... SKIP: 
Such-and-such failed. Skipping all tests in foo.py 

---------------------------------------------------------------------- 
Ran 1 test in 0.002s 

OK (SKIP=1) 
+0

Nie wiem, czy to działałoby w * module * zasięgu; 'loader.py' wydaje się sugerować, że moduł się nie powiedzie, jeśli wyśle ​​* dowolny * wyjątek. – nneonneo

+0

Próbowałem go uruchomić testy z nosetests i działało dobrze. Edytowanie odpowiedzi, aby dodać rzeczywiste wyjście ... –

+2

'nosetests'! =' Unittest', chociaż używają tej samej biblioteki. Jestem pewien, że nie powiedzie się za zwykłe "unittest". – nneonneo

2

Spróbuj definiowania niestandardowych load_tests funkcji w module:

import unittest 
try: 
    (testcases) 
except ImportError as e: 
    def load_tests(*args, **kwargs): 
     print("Failed to load tests: skipping") 
     return unittest.TestSuite() # no tests 
+1

Podoba mi się to podejście. Prawdopodobnie byłoby lepiej, gdyby używał mechanizmu SkipTest zamiast "print", ponieważ to wyjście może zostać zagłuszone w wielu innych wynikach testu/wynikach. –

+0

Jest to możliwe. Wystarczy, że 'TestSuite' zawiera fikcyjny test, który mówi, że został pominięty. (Moduł ładujący 'unittest' działa podobnie, generując przypadki testowe z błędami, jeśli np. Import nie powiedzie się). – nneonneo

6

Okazało się, że za pomocą skipTest w Setup działa dobrze. Jeśli potrzebujesz modułu zaimportowanego, użyj bloku try, by ustawić np. module_failed = Prawda, aw ustawieniu setUp wywołanie skipTest, jeśli jest ustawione. Ten informuje właściwą liczbę pominięć testowych tylko krótki bloku try poszkodowanym:

import unittest 

try: 
    import my_module 
    module_failed = False 
except ImportError: 
    module_failed = True 

class MyTests(unittest.TestCase): 
    def setUp(self): 
     if module_failed: 
      self.skipTest('module not tested') 

    def test_something(self): 
      #... 
3

solution proponowany przez robót OTUS i jest łatwiejsze niż przyjętego rozwiązania w mojej opinii. Ale jest co najmniej jedna wada.Jeśli zapytanie my_module w dekoratora pominąć jeden test taki jak

@unittest.skipIf(my_module.support_foo, 'foo not supported') 
def test_foo(self): 
... 

dostaniesz NameError: name 'my_module' is not defined. Roztwór umieszcza przeskakiwanie wewnątrz definicji funkcji:

def test_foo(self): 
    if not my_module.support_foo: 
     self.skipTest('foo not supported') 
0

łączące wymienione odpowiedzi i za pomocą this answer:

import unittest 
def module_exists(module_name): 
    try: 
     __import__(module_name) 
    except ImportError: 
     return False 
    else: 
     return True 

class TestClass(unittest.TestCase): 

    @unittest.skipUnless(module_exists("moduleA"), 'ModuleA not installed') 
    def test_something(self): 
     # test something with moduleA 
1

Na pytona 2.7+ (lub za pomocą unittest2 backportu):

... 

import unittest 

def setUpModule(): 
    try: 
     import something 
    except ImportError as err: 
     raise unittest.SkipTest(str(err)) 

class Tests(unittest.TestCase): 
    @classmethod 
    def setUpClass(cls): 
     try: 
      import something 
     except ImportError as err: 
      raise unittest.SkipTest(str(err)) 
... 
Powiązane problemy