2010-10-12 16 views
10

Używam modułu python unittest do wykonania wielu testów; jest jednak bardzo powtarzalny.Jak przetestować to samo twierdzenie dla dużej ilości danych

Mam wiele danych, które chcę wielokrotnie sprawdzać, sprawdzając poprawność. Muszę jednak zdefiniować test dla każdego.

Na przykład chcę zrobić coś podobnego do tego. Wiem, że mógłbym to zrobić za pomocą generatora (znalazłem go w poprzednim wątku tutaj). Ale czy istnieją alternatywy, może nawet przy użyciu innego modułu testowego?

Wszelkie sugestie byłyby świetne.


import unittest 

class TestData(unittest.TestCase): 
    def testNumbers(self): 
     numbers = [0,11,222,33,44,555,6,77,8,9999] 
     for i in numbers: 
      self.assertEqual(i, 33) 
+0

Co z tego? Wygląda świetnie. –

+0

Zasadniczo, gdy tylko twierdzenie jest prawdziwe, przestanie ono działać. – Mark

Odpowiedz

1

W innym poście ja natknęliśmy Nose Tests lepiej nadaje się do danych napędzane testów.


class Test_data(): 
    def testNumbers(): 
     numbers = [0,11,222,33,44,555,6,77,8,9999] 
     for i in numbers: 
      yield checkNumber, num 

def checkNumber(num): 
    assert num == 33 

Powyższy kod wykonuje dokładnie to samo, co mój pierwszy wpis. Import nie jest potrzebny, wystarczy napisać klasę python.

można wykonać testów wpisując:

nosetests filename

2

Problem z systemem twierdzeń w pętli jest to, że jeśli jeden z tych twierdzeń nie, nie wiem, który to spowodował wartość (w przykładzie, to nie na 0, ale nie wiem, że do czasu debugowania). Z drugiej strony powtarzanie self.assertEqual(i, 33) jest jeszcze gorszym pomysłem, ponieważ wprowadza duplikację kodu.

To, co robię w moim teście, to utworzenie w teście prostej, krótko nazwanej funkcji wewnętrznej i wywołanie jej za pomocą różnych argumentów. Więc funkcja będzie wyglądać następująco:

import unittest 

class TestData(unittest.TestCase): 
    def testNumbers(self): 
     def eq(i): 
      self.assertEqual(i, 33) 
     eq(0) 
     eq(11) 
     eq(222) 
     eq(33) 
     eq(44) 
     eq(555) 
     ... 

W ten sposób, gdy nie powiedzie się 0 twierdzenie, od razu zobaczyć go na ślad stosu drukowanych przez moduł unittest.

+0

Widzę, co robisz. To dobry pomysł. Ale za pierwszym razem, gdy trafi 33, przestanie działać dla reszty kodu. – Mark

+0

Jeśli mówisz, że musisz odtworzyć urządzenie testowe dla każdego numeru, to powinieneś postępować zgodnie z sugestią Billa Gribla i dynamicznie konstruować TestSuite. – DzinX

5

Być może warto rozważyć użycie klasy unittest.TestSuite, która pozwoli na dynamiczne konstruowanie zestawu unittest.TestCase wystąpień, które będą uruchamiane oddzielnie. Twoja podklasa unittest.TestCase powinna definiować tylko jedną metodę testową, przy czym klasa akceptuje parametr konstrukcyjny przekazujący wartość, aby przetestować dla tej konkretnej instancji.

9

Przykładowy kod dla rozwiązania sugerowane przez Billa Gribble mógłby wyglądać następująco:

import unittest 

class DataTestCase(unittest.TestCase): 
    def __init__(self, number): 
     unittest.TestCase.__init__(self, methodName='testOneNumber') 
     self.number = number 

    def testOneNumber(self): 
     self.assertEqual(self.number, 33) 

    def shortDescription(self): 
     # We need to distinguish between instances of this test case. 
     return 'DataTestCase for number %d' % self.number 


def get_test_data_suite(): 
    numbers = [0,11,222,33,44,555,6,77,8,9999] 
    return unittest.TestSuite([DataTestCase(n) for n in numbers]) 

if __name__ == '__main__': 
    testRunner = unittest.TextTestRunner() 
    testRunner.run(get_test_data_suite()) 
1

ddt library został zbudowany w celu rozwiązania dokładnie, o co prosicie.

Na przykład:

import ddt 
import unittest 

@ddt.ddt 
class EvalTests(unittest.TestCase): 

    @ddt.data(
      ('1', 1), 
      ('1 == 1', True), 
      ('1 == 2', False), 
      ('1 + 2', 4), ## This will fail 
    ) 
    def test_eval_expressions(self, case): 
     expr, exp_value = case 
     self.assertEqual(eval(expr), exp_value) 

a kiedy go uruchomić, można dostać 4 testami, a nie tylko jednego:

$ python -m unittest -v test_eval.py 
test_eval_expressions_1___1___1_ (test_eval.EvalTests) ... ok 
test_eval_expressions_2___1__1___True_ (test_eval.EvalTests) ... ok 
test_eval_expressions_3___1__2___False_ (test_eval.EvalTests) ... ok 
test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) ... FAIL 

====================================================================== 
FAIL: test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/usr/lib/python/lib/site-packages/ddt.py", line 129, in wrapper 
    return func(self, *args, **kwargs) 
    File "/Work/test_eval.py", line 15, in test_eval_expressions 
    self.assertEqual(eval(expr), exp_value) 
AssertionError: 3 != 4 

---------------------------------------------------------------------- 
Ran 4 tests in 0.002s 

FAILED (failures=1) 

Uwaga, ddt próbuje wymyślić nazwy dla wygenerowany Najlepsi współtwórcy.

zainstalować go z pip:

pip install ddt 
0

Spin-off this odpowiedź, która nie dość pracy dla mnie. Gdzie nie mam do czynienia z dużymi danymi , musiałem uruchomić te same testy z różnymi wejściami. Poniższe testy używają metod, które chcę spersonalizować.

Wymagane jest wykonanie obu testów z tą samą konfiguracją.

class Tests(unittest.TestCase): 

    def test_a_uses_b(self): 
     a = create_a() 
     b = create_b() 
     a.b = b 
     self.assertIs(b.a, a) 

    def test_b_uses_a(self): 
     a = create_a() 
     b = create_b() 
     b.a = a 
     self.assertIs(a.b, b) 

instancji TestSuite i TestCase siebie, omijając ładowarka testową, spowodowała błąd, ponieważ oczekuje jedną metodę, zwaną runTest.

Wynik był następujący:

class Tests(unittest.TestCase): 

    def __init__(self, create_a, create_b): 
     super().__init__() 
     self.create_b = create_b 
     self.create_a = create_a 

    def test_a_uses_b(self): 
     a = self.create_a() 
     b = self.create_b() 
     a.b = b 
     self.assertIs(b.a, a) 

    def test_b_uses_a(self): 
     a = self.create_a() 
     b = self.create_b() 
     b.a = a 
     self.assertIs(a.b, b) 


class TestPair1(Tests): 
    def __init__(self): 
     super().__init__(create_a1, create_b1) 


class TestPair2(Tests): 
    def __init__(self): 
     super().__init__(create_a2, create_b2) 
Powiązane problemy