2010-02-01 9 views
66

JUnit 4.8 zawiera nową, ładną funkcję o nazwie "Kategorie", która umożliwia grupowanie określonych rodzajów testów. Jest to bardzo przydatne, np. mieć oddzielne testy dla wolnych i szybkich testów. Znam rzeczy wymienione w JUnit 4.8 release notes, ale chciałbym wiedzieć, w jaki sposób mogę faktycznie uruchomić wszystkie testy opisane w pewnej kategorii.Jak uruchomić wszystkie testy należące do określonej kategorii w JUnit 4

W JUnit 4.8 Release Notes przedstawiają definicję przykład nowożeńców, gdzie SuiteClasses adnotacja wybiera testy z określonej kategorii, aby uruchomić w następujący sposób:

@RunWith(Categories.class) 
@IncludeCategory(SlowTests.class) 
@SuiteClasses({ A.class, B.class }) // Note that Categories is a kind of Suite 
public class SlowTestSuite { 
    // Will run A.b and B.c, but not A.a 
} 

Czy ktoś wie jak mogę uruchomić wszystkie testy w kategorii SlowTests ? Wygląda na to, że musisz mieć adnotację SuiteClasses ...

+1

Wit. Mam pytanie, które jest powiązane. zapraszam do dzwonienia w: http://stackoverflow.com/questions/15776718/using-junit-categories-vs-simply-organising-logical-test-categories-inparse – amphibient

Odpowiedz

59

Odkryłem jeden z możliwych sposobów osiągnięcia tego, czego chcę, ale nie uważam tego za najlepsze możliwe rozwiązanie, ponieważ polega ono na bibliotece ClassPathSuite, która nie jest częścią JUnit.

zdefiniować zestaw testów dla powolnych testów tak:

@RunWith(Categories.class) 
@Categories.IncludeCategory(SlowTests.class) 
@Suite.SuiteClasses({ AllTests.class }) 
public class SlowTestSuite { 
} 

alltests klasa jest zdefiniowana następująco:

@RunWith(ClasspathSuite.class) 
public class AllTests { 
} 

musiałem użyć klasy ClassPathSuite z ClassPathSuite projekcie tutaj. Znajdziesz wszystkie zajęcia z testami.

+4

To właściwie całkiem rozsądne rozwiązanie. Dzięki za anwesering własne pytanie, ponieważ jest naprawdę dobry :-) –

+0

Dla każdego, kto zastanawia się, jak zautomatyzować prowadzenie kategorii testów (z tą dokładną konfiguracją) za pomocą Ant, [to pytanie] (http://stackoverflow.com/questions/6226026/how-to-run-all-junit-tests-in-a-category-suite-with-ant) mogą być przydatne. – Jonik

+3

Jako uzupełnienie mojego pytania http://stackoverflow.com/q/2698174/59470 i szczegółowe wyjaśnienie dodałem wpis na blogu: http://novyden.blogspot.com/2011/06/using-junit-4-categories -zamienić.html – topchef

1

Nie jestem pewien, jaki jest dokładnie twój problem.

Wystarczy dodać wszystkie testy do pakietu (lub hirachy pakietów). Następnie użyj adnotacji Category Runner i Include/ExcludeCategory, aby określić kategorie, które chcesz uruchomić.

Dobrym pomysłem może być posiadanie jednego zestawu zawierającego wszystkie testy i kilka oddzielnych apartamentów odnoszących się do pierwszego, określających inny zestaw kategorii, które są w toku.

+19

Moim problemem jest to, że mam tysiące testów i Nie chcę ręcznie dodawać ich do żadnych pakietów. Chcę tylko, żeby testy z pewną kategorią były uruchamiane. JUnit nie powinien być tak trudny, aby dowiedzieć się, które testy mają pewne adnotacje, ponieważ tak naprawdę to robi, kiedy znajduje metody testowania. – Kaitsu

1

Nie bezpośrednią odpowiedź na Twój problem, ale może można poprawić ogólne podejście ...

Dlaczego wasze testy wolno? Może konfiguracja trwa długo (baza danych, I/O itp.), Może testy testują za dużo? W takim przypadku oddzieliłbym rzeczywiste testy jednostkowe od "długich", które często są testami integracyjnymi.

W moich konfiguracjach mam env, gdzie testy jednostkowe są uruchamiane często, a testy integracyjne ciągle, ale rzadziej (np. Po każdym zatwierdzeniu w kontroli wersji). Nigdy nie pracowałem z grupowaniem na testy jednostkowe, ponieważ powinny one być luźno połączone w całość. Pracuję tylko z grupowaniem i relacją przypadków testowych w konfiguracyjnych testach integracji (ale z TestNG).

Ale dobrze wiedzieć, że JUnit 4.8 wprowadził pewne funkcje grupujące.

+1

Dzięki Manuel za komentarze! Nie potrzebuję oddzielać testów jednostkowych, ale używam JUnit również do testów integracyjnych i chcę oddzielić je od testów jednostkowych. Spojrzałem także na TestNG i wydaje się, że testowanie (a nie tylko testowanie jednostkowe) jest przyjemniejsze niż JUnit. Ma również lepszą dokumentację i dobrą książkę. – Kaitsu

7

Oto niektóre z głównych różnic między TestNG i JUnit jeśli chodzi o grupy (lub grup, jak JUnit nazywa je):

  • JUnit użytkownika są wpisane (adnotacji) podczas TestNG są struny. Dokonałem tego wyboru, ponieważ chciałem móc używać wyrażeń regularnych podczas uruchamiania testów, na przykład "uruchom wszystkie testy należące do grupy" bazy danych * ".Ponadto tworzenie nowej adnotacji za każdym razem, gdy trzeba utworzyć nową kategorię, jest denerwujące, choć ma tę zaletę, że IDE powie od razu, gdzie ta kategoria jest używana (TestNG pokazuje to w swoich raportach).

  • TestNG bardzo wyraźnie oddziela model statyczny (kod testów) od modelu środowiska wykonawczego (które testy są uruchamiane). Jeśli chcesz uruchomić najpierw grupy "front-end", a potem "servlets", możesz to zrobić bez konieczności rekompilacji czegokolwiek. Ponieważ JUnit definiuje grupy w adnotacjach i musisz określić te kategorie jako parametry dla biegacza, zwykle musisz przekompilować swój kod za każdym razem, gdy chcesz uruchomić inny zestaw kategorii, co pokonuje cel w mojej opinii.

+0

W naszych testach JUnit stworzyliśmy wsparcie w bardzo podobny sposób do JUnit, z tą różnicą, że zamiast adnotacji @ Categories.IncludeCategory, stworzyliśmy naszą konfigurację za pomocą właściwości systemowej. Dlaczego JUnitowi nie było zbyt ciężko, aby to dla nas zrobić, to nikt inny. – Trejkaz

2

Aby uruchomić skategoryzowane testy bez określenia wszystkich z nich wyraźnie określony w @Suite.SuiteClasses adnotacji można podać własną implementację Suite. Na przykład można przedłużyć org.junit.runners.ParentRunner. Zamiast używać tablicy klas dostarczonej przez @Suite.SuiteClasses, nowa implementacja powinna wykonać wyszukiwanie skategoryzowanych testów w ścieżce klas.

Przykładem takiego podejścia jest this project. Zastosowanie:

@Categories(categoryClasses = {IntegrationTest.class, SlowTest.class}) 
@BasePackage(name = "some.package") 
@RunWith(CategorizedSuite.class) 
public class CategorizedSuiteWithSpecifiedPackage { 

} 
5

Jedną wadą rozwiązania jest to, że Kaitsu Eclipse będzie uruchamiać testy dwukrotnie, a SlowTests 3 razy, podczas uruchamiania wszystkie testy w projekcie. Dzieje się tak, ponieważ Eclipse uruchomi wszystkie testy, następnie pakiet AllTests, a następnie SlowTestSuite.

Oto rozwiązanie, które polega na tworzeniu podklas testów testowych rozwiązania Kaitsu, aby pominąć pakiety, chyba że ustawiona jest określona właściwość systemowa. Haniebny hack, ale wszystko, co do tej pory wymyśliłem.

@RunWith(DevFilterClasspathSuite.class) 
public class AllTests {} 

.

@RunWith(DevFilterCategories.class) 
@ExcludeCategory(SlowTest.class) 
@SuiteClasses(AllTests.class) 
public class FastTestSuite 
{ 
} 

.

public class DevFilterCategories extends Suite 
{ 
    private static final Logger logger = Logger 
     .getLogger(DevFilterCategories.class.getName()); 
    public DevFilterCategories(Class<?> suiteClass, RunnerBuilder builder) throws InitializationError { 
     super(suiteClass, builder); 
     try { 
      filter(new CategoryFilter(getIncludedCategory(suiteClass), 
        getExcludedCategory(suiteClass))); 
      filter(new DevFilter()); 
     } catch (NoTestsRemainException e) { 
      logger.info("skipped all tests"); 
     } 
     assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription()); 
    } 

    private Class<?> getIncludedCategory(Class<?> klass) { 
     IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); 
     return annotation == null ? null : annotation.value(); 
    } 

    private Class<?> getExcludedCategory(Class<?> klass) { 
     ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); 
     return annotation == null ? null : annotation.value(); 
    } 

    private void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError { 
     if (!canHaveCategorizedChildren(description)) 
      assertNoDescendantsHaveCategoryAnnotations(description); 
     for (Description each : description.getChildren()) 
      assertNoCategorizedDescendentsOfUncategorizeableParents(each); 
    } 

    private void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError {   
     for (Description each : description.getChildren()) { 
      if (each.getAnnotation(Category.class) != null) 
       throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods."); 
      assertNoDescendantsHaveCategoryAnnotations(each); 
     } 
    } 

    // If children have names like [0], our current magical category code can't determine their 
    // parentage. 
    private static boolean canHaveCategorizedChildren(Description description) { 
     for (Description each : description.getChildren()) 
      if (each.getTestClass() == null) 
       return false; 
     return true; 
    } 
} 

.

public class DevFilterClasspathSuite extends ClasspathSuite 
{ 
    private static final Logger logger = Logger 
     .getLogger(DevFilterClasspathSuite.class.getName()); 
    public DevFilterClasspathSuite(Class<?> suiteClass, RunnerBuilder builder) 
     throws InitializationError { 
     super(suiteClass, builder); 
     try 
     { 
      filter(new DevFilter()); 
     } catch (NoTestsRemainException e) 
     { 
      logger.info("skipped all tests"); 
     } 
    } 
} 

.

public class DevFilter extends Filter 
{ 
    private static final String RUN_DEV_UNIT_TESTS = "run.dev.unit.tests"; 

    @Override 
    public boolean shouldRun(Description description) 
    { 
     return Boolean.getBoolean(RUN_DEV_UNIT_TESTS); 
    } 

    @Override 
    public String describe() 
    { 
     return "filter if "+RUN_DEV_UNIT_TESTS+" system property not present"; 
    } 
} 

Tak w FastTestSuite wyrzutni, po prostu dodaj -Drun.dev.unit.tests = true na argumenty VM. (Należy zauważyć, że to rozwiązanie odwołuje się do zestawu szybkiego testu zamiast powolnego.)

Powiązane problemy