2015-04-21 21 views
13

Mam bardzo skomplikowany plik tests.py.Uruchamianie konkretnych testów Django (z django-nose?)

Faktycznie testy klasy i metody są generowane w czasie wykonywania w/type (w celu uwzględnienia danych wymienionych w plikach pomocniczych). Robię rzeczy w następujący sposób (patrz poniżej, aby uzyskać więcej kodzie):

klass = type(name, (TestCase,), attrs) 
setattr(current_module, name, klass) 

FYI, ze zwykłymi testowej Django biegacza, wszystkie te testy się uruchomić, gdy robi ./manage.py test myapp (dzięki setattr przedstawionym powyżej).

Co chcę zrobić, to uruchomić tylko część tych testów, bez podawania ich nazwisk ręcznie.

Na przykład, mógłbym nadać każdemu testowi "znaczniki" w nazwach klas lub nazwach metod, aby umożliwić ich filtrowanie. Na przykład chciałbym następnie wykonać: uruchomić wszystkie testy, którego nazwa metoda zawiera ciąg znaków „test_postgres_backend_”

Próbowałem za pomocą django-nose powodu -m opcji nose „s, która powinna być w stanie wybrać testy na podstawie wyrażeń regularnych, jak idealne rozwiązanie mojego problemu.

Niestety, tutaj jest to, co dzieje się przy użyciu django-nos jako biegacza testowej Django:

  • ./manage.py test myapp nie jest znalezienie automatycznie przez type -generated klas testowych (w przeciwieństwie do biegacza testowego django)
  • ani ./manage.py test -m ".*" myapp ani ./manage.py test myapp -m ".*" znaleźć żadnego testu, nawet jeśli normalne TestCase zajęcia są obecne w pliku

Więc:

  • Czy masz inny rodzaj roztworu do mojego ogólnego problemu, zamiast próbować używać django-nos -m?
  • Dzięki django-nose, wiesz, jak sprawić, aby numer -m zadziałał?

mcve

Dodaj poniższe linie do pustej myapp/tests.py pliku:

from django.test import TestCase 
from sys import modules 


current_module = modules[__name__] 


def passer(self, *args, **kw): 
    self.assertEqual(1, 1) 


def failer(self, *args, **kw): 
    self.assertEqual(1, 2) 


# Create a hundred ... 
for i in xrange(100): 
    # ... of a stupid TestCase class that has 1 method that passes if `i` is 
    # even and fails if `i` is odd 
    klass_name = "Test_%s" % i 
    if i % 2: # Test passes if even 
     klass_attrs = { 
      'test_something_%s' % i: passer 
     } 
    else:  # Fail if odd 
     klass_attrs = { 
      'test_something_%s' % i: failer 
     } 
    klass = type(klass_name, (TestCase,), klass_attrs) 

    # Set the class as "child" of the current module so that django test runner 
    # finds it 
    setattr(current_module, klass_name, klass) 

Jeśli czyni z tego biegu wyjściowego (w kolejności alphab) testem Django runnner:
F.F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F..

Jeśli zmienisz na django_nose biegacz testowy, nic się nie dzieje na ./manage.py test myapp.

Po ustaleniu tego, bym potem jak będzie w stanie uruchomić tylko metody badawcze, którego nazwa kończą się 0 (lub innego rodzaju filtrowanie regexable)

+0

http://stackoverflow.com/questions/18834188/how-to-run-a-single-test-lub-single-testcase-with-django-nose –

Odpowiedz

5

Wystąpił problem polegający na tym, że Nos określa, czy należy włączyć metodę do zestawu testów do uruchomienia, patrząc na nazwę zarejestrowaną na samej funkcji, a nie na atrybut, który daje dostęp do funkcji . Jeśli zmienię nazwę użytkownika na passer i failer na test_pass i test_fail, wówczas Nose może znaleźć testy. Zatem same funkcje muszą być nazwane w sposób, który zostanie dopasowany do tego, co jest podane do -m (lub jego wartości domyślnej).

Oto zmodyfikowany kod, który daje oczekiwane rezultaty:

from django.test import TestCase 
from sys import modules 

current_module = modules[__name__] 

def test_pass(self, *args, **kw): 
    self.assertEqual(1, 1) 

def test_fail(self, *args, **kw): 
    self.assertEqual(1, 2) 

# Create a hundred ... 
for i in xrange(100): 
    # ... of a stupid TestCase class that has 1 method that passes if `i` is 
    # even and fails if `i` is odd 
    klass_name = "Test_%s" % i 
    if i % 2: # Test passes if even 
     klass_attrs = { 
      'test_something_%s' % i: test_pass 
     } 
    else:  # Fail if odd 
     klass_attrs = { 
      'test_something_%s' % i: test_fail 
     } 
    klass = type(klass_name, (TestCase,), klass_attrs) 

    # Set the class as "child" of the current module so that django test runner 
    # finds it 
    setattr(current_module, klass_name, klass) 

# This prevents Nose from seeing them as tests after the loop is over. 
test_pass = None 
test_fail = None 

bez dwóch ostatnich zadań do None, Nos weźmie pod uwagę dwie najwyższe funkcje poziomu za testy moduł szczebla i potrwa do nich oprócz do testów na zajęciach.

Innym sposobem, aby uzyskać takie same wyniki byłoby zdefiniowanie __test__ na swoje dwie funkcje:

def passer(self, *args, **kw): 
    self.assertEqual(1, 1) 
passer.__test__ = 1 

def failer(self, *args, **kw): 
    self.assertEqual(1, 2) 
failer.__test__ = 1 

A na końcu pliku:

# This prevents Nose from seeing them as tests after the loop is over. 
passer = None 
failer = None 

nos wygląda na obecność tych na funkcjach i jeśli jest obecny i ustawiony na wartość jest uważany za prawdziwy, to przyjmie funkcję jako przypadek testowy.

Logika regulujące wybór metod można znaleźć w nos za selector.py pliku, na wantMethod method:

def wantMethod(self, method): 
     """Is the method a test method? 
     """ 
     try: 
      method_name = method.__name__ 
     except AttributeError: 
      # not a method 
      return False 
     if method_name.startswith('_'): 
      # never collect 'private' methods 
      return False 
     declared = getattr(method, '__test__', None) 
     if declared is not None: 
      wanted = declared 
     else: 
      wanted = self.matches(method_name) 
     plug_wants = self.plugins.wantMethod(method) 
     if plug_wants is not None: 
      wanted = plug_wants 
     log.debug("wantMethod %s? %s", method, wanted) 
     return wanted 

nie widzę wyraźny sposób korzystania -m aby uruchomić tylko kilka testów, jak chcesz to. Problem polega na tym, że -m identycznie pasuje do nazw plików, reżyserów, modułów, klas i funkcji. Jeśli ustawisz coś takiego, jak -m0$, wszystkie poszczególne części, które właśnie zaznaczyłem, muszą być zgodne z wyrażeniem regularnym dla testu, który ma zostać wybrany. (Nos nie łączy ich, a następnie pasuje do kombinacji.) Istnieje możliwość indywidualnej listy testów w wierszu poleceń, ale jest to słaby zamiennik dopasowania do wyrażenia regularnego.

+0

Rzeczywiście, masz rację, aby sposób rozpoznać funkcje przez nos .Ale jest prostszy sposób: włóż 'def test_passer' w pętlę! Ale jeśli chodzi o opcję '-m', wciąż pracuję nad spełnieniem moich potrzeb. Bardzo szczegółowa odpowiedź w każdym razie, przyjmie to. – lajarre

2

Ogólnie można uruchomić konkretnego przetestuj coś podobnego:

# assuming your tests are in core/tests.py 
python manage.py test core.tests:CoreTestCase.my_specific_test 

Czy próbowałeś tego podejścia?

+1

Tak. Kiedy mówię "bardzo skomplikowany plik testowy", oznacza to, że w module generowanych jest około stu klas testowych. Jak mówię, generuję klasy testowe w czasie wykonywania, w zależności od danych Aux. Robię to wszystko, szczególnie dlatego, że nie wiem, ile testów istnieje i nie chcę być w stanie poradzić sobie z nimi ręcznie. Dlatego mówię o filtrowaniu wyrażeń regularnych na liście nazw testów, ponieważ mogłem określić znaczniki w nazwach metod, aby móc wykonywać filtry regex ... – lajarre

Powiązane problemy