Uruchamiasz równolegle testy junit w kompilacji Mavena?


110

Używam JUnit 4.4 i Maven i mam wiele długotrwałych testów integracyjnych.

Jeśli chodzi o zrównoleglenie zestawów testów, istnieje kilka rozwiązań, które pozwalają mi równolegle uruchamiać każdą metodę testową w jednej klasie testowej. Ale to wszystko wymaga, abym zmienił testy w taki czy inny sposób.

Naprawdę myślę, że byłoby dużo czystszym rozwiązaniem równoległe uruchamianie X różnych klas testowych w wątkach X. Mam setki testów, więc nie obchodzi mnie wątkowanie poszczególnych klas testowych.

Czy jest na to sposób?

Odpowiedzi:


75

Użyj wtyczki maven:

<build>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.7.1</version>
        <configuration>
            <parallel>classes</parallel>
            <threadCount>5</threadCount>
        </configuration>
    </plugin>
    </plugins>
</build>

12
<parallel> jest faktycznie obsługiwany przez surefire, jeśli używasz Junit 4.7 lub nowszego.
Pewny

42

Od junit 4.7 można teraz uruchamiać testy równolegle bez używania TestNG. Właściwie było to możliwe od wersji 4.6, ale w 4.7 wprowadzono szereg poprawek, które sprawią, że będzie to opłacalna opcja. Możesz także przeprowadzić równoległe testy ze sprężyną, o których możesz przeczytać tutaj


1
Strona, do której prowadzi łącze, zawiera informację „w przypadku większości rozwiązań dwurdzeniowych uruchamianie z równoległymi wątkami nigdy nie jest szybsze niż uruchamianie bez wątków”. Jest to ciągle aktualne?
Raedwald

2
Pomyślałbym, że jeśli twoje testy wykonają jakiekolwiek IO, nadal będą na tym korzystać. Na przykład, jeśli testy jednostkowe są bardziej podobne do testów integracyjnych i trafiają do bazy danych, równoległe uruchamianie powinno je przyspieszyć.
Dave

@Raedwald Nie oczekuj zbyt wiele w przypadku krótkich testów jednostkowych niezwiązanych z io, to próbuję powiedzieć. Nowsze wersje surefire są również lepsze / wydajniejsze niż 2.5 opisane w poście, więc możesz uzyskać nieco lepsze wyniki.
krosenvold

3
Stwierdzasz, że jest to możliwe, ale czy możesz dołączyć link do wyjaśnienia, jak to zrobić? Twój drugi link jest dla „z wiosny”, który nie jestem zainteresowany.
Cory Kendall

Link @krosenvold? Próbuję znaleźć wbudowane rozwiązanie.
Ilan Biala

10

Zainspirowany eksperymentalnym programem ParallelComputer firmy JUnit, stworzyłem własne programy do biegania ParallelSuite i ParallelParameterized . Korzystając z tych programów uruchamiających, można łatwo zrównoleglać zestawy testów i testy parametryzowane.

ParallelSuite.java

public class ParallelSuite extends Suite {

    public ParallelSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {

        super(klass, builder);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(4);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

ParallelParameterized.java

public class ParallelParameterized extends Parameterized {

    public ParallelParameterized(Class<?> arg0) throws Throwable {

        super(arg0);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(8);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

Użycie jest proste. Po prostu zmień wartość adnotacji @RunWith na jedną z tych klas Parallel * .

@RunWith(ParallelSuite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {}

5

tempus-fugit oferuje coś podobnego, sprawdź szczegóły w dokumentacji. Opiera się na JUnit 4.7 i po prostu zaznacz swój test@RunWith(ConcurrentTestRunner) .

Twoje zdrowie


3

Możesz sprawdzić bibliotekę open source - Test Load Balancer . Robi dokładnie to, o co prosisz - równolegle uruchamiaj różne klasy testowe. To integruje się na poziomie ant-junit, dzięki czemu nie musisz w żaden sposób zmieniać swoich testów. Jestem jednym z autorów biblioteki.

Pomyśl także o tym, aby nie uruchamiać ich w wątkach, ponieważ możesz potrzebować piaskownicy na poziomie procesu. Na przykład, jeśli trafiasz do bazy danych w testach integracji, nie chcesz, aby jeden test zakończył się niepowodzeniem, ponieważ inny test dodał dane w innym wątku. W większości przypadków testy nie są pisane z myślą o tym.

Wreszcie, jak rozwiązałeś dotychczas ten problem?


2

TestNG może to zrobić (to był mój pierwszy odruch - wtedy zobaczyłem, że masz już wiele przypadków testowych).

W przypadku JUnit spójrz na połączenie równoległe .


3
Niestety nie jest to odpowiedź na zadane przeze mnie pytanie. parallel-junit działa tylko w jednej klasie testowej. TestNG działa również tylko w ramach jednej klasy, a moje testy nie są testami TestNG.
krosenvold

@PlatinumAzure: Zaktualizowałem łącze. Nie wiem, jak ten projekt jest utrzymywany. Ostatnio zadano inne pytanie o dystrybucję wykonywania testów junit na kilku maszynach .
filant

2

Testy można uruchamiać równolegle przy użyciu komputera ParallelComputer dostarczonego przez firmę Junit. Oto mały fragment na początek.

Class[] cls = { TestCase1.class, TestCase2.class };
Result result = JUnitCore.runClasses(ParallelComputer.classes(), cls);
List<Failure> failures = result.getFailures();

Pomoże to, gdy musisz uruchomić testy z kodu, ponieważ nie ma on żadnych zależności od Maven ani innych narzędzi do zarządzania kompilacją.

Zwróć uwagę, że spowoduje to równoległe uruchomienie wszystkich przypadków testowych, jeśli masz jakiekolwiek zależności między różnymi przypadkami testowymi, może to spowodować fałszywe alarmy. I tak NIE POWINIENEŚ poddawać się niezależnym testom.


0

Inny wybór: Punner, nowy równoległy junit runner i wtyczka maven. Nie musisz zmieniać swojego kodu, skopiuj go do swojego pom.xml:

<!-- Disable default surefire based testing -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.20</version>
  <configuration>
    <skip>true</skip>
  </configuration>
</plugin>

<plugin>
  <groupId>com.github.marks-yag</groupId>
  <artifactId>punner-maven-plugin</artifactId>
  <version>${version}</version>
  <configuration>
  </configuration>
  <executions>
    <execution>
      <id>test</id>
      <phase>test</phase>
      <goals>
        <goal>test</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Punner może równolegle uruchamiać metody testowe, może utrzymywać wyniki testowe oddzielnie i czyste.

Punner zredukuje wyjście konsoli mvn, na przykład:

[INFO] --- punner-maven-plugin:0.9.13:test (test) @ ipc ---
[INFO] Punner report directory: /Users/guile/workspace/ipc/target/punner-reports
[INFO]
[INFO] com.github.yag.ipc.IPCTest.testConnectionHandler.............. PASSED
[INFO] com.github.yag.ipc.IPCTest.testSequence....................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testPartialContent................. PASSED
[INFO] com.github.yag.ipc.IPCTest.testResponseContent................ PASSED
[INFO] com.github.yag.ipc.IPCTest.testPingPong....................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testServerClose.................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testServerSideHeartbeatTimeout..... PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientSideHeartbeatTimeout..... PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientSideHeartbeat............ PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientReconnect................ PASSED
[INFO]
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.952 sec, Time saved: 25.919 sec.

Punner produkuje z pewnością kompatybilne dane wyjściowe, możesz również uzyskać nieprzetworzone dane dziennika i raport w formacie przeceny z katalogu raportów:

  ipc git:(develop) ll target/punner-reports
total 104
-rw-r--r--   1 guile  staff    11K Oct 15 23:07 TEST-com.github.yag.ipc.IPCTest.xml
-rw-r--r--   1 guile  staff   298B Oct 15 23:07 com.github.yag.ipc.IPCTest.txt
drwxr-xr-x  12 guile  staff   384B Oct  8 00:50 logs
-rw-r--r--   1 guile  staff    33K Oct 15 23:07 report.md

Punner to mój osobisty projekt, napisałem Punner, aby przyspieszyć fazę testów jednostkowych innych projektów, takich jak framework IPC, precyzyjne blokowanie, obsługa dzienników, silnik rozproszonego przepływu pracy, itp. To zaoszczędziło mi dużo czasu.

Punner nie obsługuje jeszcze niektórych zaawansowanych funkcji. Bardzo się cieszę, gdybyś mógł spróbować i przekazać mi swoją opinię.


-3

Możesz zmienić swój test na TestNg w ciągu minuty (wystarczy zmienić import), TestNG jest najlepszy w testowaniu równoległym.


-3

Możesz wypróbować Gridgain, który umożliwia uruchamianie dystrybucji testów w siatce obliczeniowej.


1
Wypróbowałem rozwiązanie GridGain i miałem dwa poważne problemy. Po pierwsze, musisz powiedzieć GridGain, aby wykluczył ze ścieżki klas twojego zadania grid wszystko, czego używa GridGain, np. Spring i wiele rzeczy z Apache Commons. Po drugie, sieciowe ładowanie klas, choć genialny pomysł, nie działa dla bibliotek, które chcą przeszukiwać ścieżkę klas, np. Wiosna
Graham Lea
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.