Python unittest-przeciwieństwo twierdzeń?

Chcę napisać test, aby ustalić, że wyjątek nie jest podniesiony w danych okolicznościach.

Łatwo jest sprawdzić, czy wyjątek jest podniesiony ...

sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath) 

... ale jak możesz zrobić odwrotnie .

Coś takiego, czego szukam ...

sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath) 
Author: glaucon, 2010-12-01

7 answers

def run_test(self):
    try:
        myFunc()
    except ExceptionType:
        self.fail("myFunc() raised ExceptionType unexpectedly!")
 277
Author: DGH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-06 15:26:09

Wystarczy wywołać funkcję. Jeśli spowoduje to wystąpienie wyjątku, struktura testów jednostkowych oznaczy to jako błąd. Możesz dodać komentarz, np.:

sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)
 51
Author: user9876,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-30 23:37:08

Hi-chcę napisać test, aby ustalić, że wyjątek nie jest podniesiony w danych okolicznościach.

To domyślne założenie -- wyjątki nie są podnoszone.

Jeśli nie powiesz nic więcej, to jest to zakładane w każdym teście.

Nie musisz pisać żadnego twierdzenia dla tego.

 49
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-01 00:02:50

Jestem oryginalnym plakatem i zaakceptowałem powyższą odpowiedź przez DGH bez uprzedniego użycia jej w kodzie.

Kiedy już użyłem, zdałem sobie sprawę, że trzeba trochę poprawić, aby rzeczywiście zrobić to ,czego potrzebowałem (aby być uczciwym DGH powiedział "lub coś podobnego" !).

Pomyślałem, że warto tu wrzucić tweak dla dobra innych:

    try:
        a = Application("abcdef", "")
    except pySourceAidExceptions.PathIsNotAValidOne:
        pass
    except:
        self.assertTrue(False)

To, co próbowałem tutaj zrobić, to upewnić się, że w przypadku próby utworzenia instancji obiektu aplikacji drugim argumentem spacji jest pySourceAidExceptions./ Align = "left" /

Wierzę, że użycie powyższego kodu (w dużej mierze na podstawie odpowiedzi DGH) to zrobi.

 13
Author: glaucon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-06 03:55:56

Jeśli przekazujesz klasę wyjątku do assertRaises(), dostarczany jest menedżer kontekstu. Może to poprawić czytelność testów:

# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
    application = Application("abcdef", "")

Pozwala to przetestować przypadki błędów w kodzie.

W tym przypadku testujesz PathIsNotAValidOne jest podniesiony, gdy przekazujesz nieprawidłowe parametry do konstruktora aplikacji.

 2
Author: hiwaylon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 10:10:39

Można zdefiniować assertNotRaises poprzez ponowne wykorzystanie około 90% oryginalnej implementacji assertRaises w module unittest. Dzięki takiemu podejściu otrzymujesz metodę assertNotRaises, która oprócz stanu odwróconej awarii zachowuje się identycznie jak assertRaises.

TLDR I live demo

Zaskakująco łatwo jest dodać metodę assertNotRaises do unittest.TestCase (napisanie tej odpowiedzi Zajęło mi około 4 razy więcej czasu niż napisanie kodu). Oto demo metody assertNotRaises w działaniu. Just Jak assertRaises, można albo przekazać wywołanie i args do assertNotRaises, albo użyć go w instrukcji with. Demo live zawiera przypadki testowe, które pokazują, że assertNotRaises działa zgodnie z przeznaczeniem.

Szczegóły

Implementacja assertRaises w unittest jest dość skomplikowana, ale przy odrobinie sprytnego podklasowania można nadpisać i odwrócić stan jego awarii.

assertRaises jest krótką metodą, która w zasadzie tworzy instancję klasy unittest.case._AssertRaisesContext i zwraca it (zobacz jego definicję w module unittest.case). Możesz zdefiniować własną klasę _AssertNotRaisesContext poprzez podklasowanie _AssertRaisesContext i nadpisanie jej metody __exit__:

from unittest.case import _AssertRaisesContext

class _AssertNotRaisesContext(_AssertRaisesContext):
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            self.exception = exc_value.with_traceback(None)

            try:
                exc_name = self.expected.__name__
            except AttributeError:
                exc_name = str(self.expected)

            if self.obj_name:
                self._raiseFailure("{} raised by {}".format(exc_name,
                    self.obj_name))
            else:
                self._raiseFailure("{} raised".format(exc_name))

        else:
            traceback.clear_frames(tb)

        return True

Normalnie definiujesz klasy przypadków testowych poprzez dziedziczenie z TestCase. Jeśli zamiast tego dziedziczysz z podklasy MyTestCase:

class MyTestCase(unittest.TestCase):
    def assertNotRaises(self, expected_exception, *args, **kwargs):
        context = _AssertNotRaisesContext(expected_exception, self)
        try:
            return context.handle('assertNotRaises', args, kwargs)
        finally:
            context = None

Wszystkie twoje przypadki testowe będą teraz miały metodę assertNotRaises dostępną dla nich.

 2
Author: tel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 20:15:33

Uznałem, że przydaje się łatanie małp unittest w następujący sposób:

def assertMayRaise(self, exception, expr):
  if exception is None:
    try:
      expr()
    except:
      info = sys.exc_info()
      self.fail('%s raised' % repr(info[0]))
  else:
    self.assertRaises(exception, expr)

unittest.TestCase.assertMayRaise = assertMayRaise

To wyjaśnia intencję podczas testowania na brak wyjątku:

self.assertMayRaise(None, does_not_raise)

Upraszcza to również testowanie w pętli, co często robię:

# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
  self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))
 1
Author: AndyJost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-16 19:15:27