Maven 빌드에서 병렬로 junit 테스트를 실행합니까?


110

JUnit 4.4와 Maven을 사용하고 있으며 장기 실행 통합 테스트가 많이 있습니다.

테스트 스위트 병렬화와 관련하여 단일 테스트 클래스에서 병렬로 각 테스트 메소드를 실행할 수있는 몇 가지 솔루션이 있습니다. 그러나이 모든 것들은 내가 어떤 식 으로든 테스트를 변경해야합니다.

X 스레드에서 X 개의 다른 테스트 클래스를 병렬로 실행하는 것이 훨씬 더 깨끗한 솔루션이라고 생각합니다. 수백 개의 테스트가 있으므로 개별 테스트 클래스를 스레딩하는 데는 신경 쓰지 않습니다.

이렇게 할 수있는 방법이 있습니까?

답변:


75

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
Junit 4.7 이상을 사용하는 경우 <parallel>은 실제로 surefire에서 지원됩니다. 확실한 가이드
jontejj apr

42

junit 4.7부터 TestNG를 사용하지 않고 병렬로 테스트를 실행할 수 있습니다. 실제로 4.6 이후로 가능했지만 4.7에서는 실행 가능한 옵션이 될 수있는 많은 수정 사항이 있습니다. 여기에서 읽을 수있는 spring으로 병렬 테스트를 실행할 수도 있습니다.


1
링크 된 페이지에는 "대부분의 듀얼 코어 솔루션의 경우 병렬 스레드로 실행하는 것이 현재 스레드되지 않은 실행보다 빠르지 않습니다"라고 말합니다. 그래도 그래요?
Raedwald 2011

2
테스트에서 IO를 수행하면 여전히 이익이 될 것이라고 생각합니다. 예를 들어 단위 테스트가 통합 테스트와 비슷하고 데이터베이스를 적중하는 경우 병렬로 실행하면 속도가 빨라집니다.
Dave

@Raedwald 짧은 비 io 바인딩 단위 테스트에 대해 너무 많은 것을 기대 하지 마십시오 . 최신 버전의 surefire는 게시물에 설명 된 2.5보다 더 좋고 / 더 효율적이므로 약간 더 나은 결과를 얻을 수 있습니다.
krosenvold

3
가능하다고 말하지만 방법에 대한 설명에 대한 링크를 포함 할 수 있습니까? 두 번째 링크는 내가 관심이 아니에요하는 "봄"입니다.
코리 켄달

@krosenvold 링크? 기본 제공 솔루션을 찾기 위해 고군분투하고 있습니다.
Ilan Biala

10

JUnit의 실험적인 ParallelComputer 실행기 에서 영감을 받아 나만의 ParallelSuiteParallelParameterized 실행기를 구축했습니다 . 이러한 실행기를 사용하면 테스트 스위트와 매개 변수화 된 테스트를 쉽게 병렬화 할 수 있습니다.

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);
                }
            }
        });
    }
}

사용법은 간단합니다. @RunWith 주석 값을 이러한 Parallel * 클래스 중 하나로 변경하기 만하면 됩니다.

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

5

tempus-fugit 은 비슷한 것을 제공합니다. 자세한 내용은 문서를 확인하세요. JUnit 4.7에 의존하며 테스트를 @RunWith(ConcurrentTestRunner).

건배


3

오픈 소스 라이브러리 인 Test Load Balancer를 확인할 수 있습니다 . 요청한대로 정확하게 수행합니다. 다른 테스트 클래스를 병렬로 실행합니다. 이것은 ant-junit 수준에서 통합되므로 어쨌든 테스트를 변경할 필요가 없습니다. 저는 도서관의 저자 중 한 명입니다.

또한 프로세스 수준 샌드 박스가 필요할 수 있으므로 스레드에서 실행하지 않는 것이 좋습니다. 예를 들어, 통합 테스트에서 DB에 도달하는 경우 다른 테스트가 다른 스레드에 일부 데이터를 추가했기 때문에 한 테스트가 실패하는 것을 원하지 않습니다. 대부분의 경우 테스트는이를 염두에두고 작성되지 않습니다.

마지막으로 지금까지이 문제를 어떻게 해결 했습니까?


2

TestNG는 그렇게 할 수 있습니다 (이것이 저의 첫 번째 반사 였고 이미 많은 테스트 케이스를 가지고있는 것을 보았습니다).

JUnit의 경우 parallel-junit를 살펴보십시오 .


3
불행히도 이것은 내가 묻는 질문에 대한 답이 아닙니다. parallel-junit은 단일 테스트 클래스 내에서만 실행됩니다. TestNG는 또한 단일 클래스 내에서만 실행되며 내 테스트는 TestNG 테스트가 아닙니다.
krosenvold

@PlatinumAzure : 링크를 업데이트했습니다. 이 프로젝트가 어떻게 유지되고 있는지 모르겠습니다. 최근 에 여러 머신에 junit 테스트 실행배포 하기위한 또 다른 질문이 제기되었습니다 .
philant

2

Junit 자체에서 제공하는 ParallelComputer를 사용하여 테스트를 병렬로 실행할 수 있습니다. 시작하는 데 도움이되는 작은 스 니펫이 있습니다.

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

Maven 또는 기타 빌드 관리 도구에 대한 종속성이 없으므로 코드에서 테스트를 실행해야 할 때 도움이됩니다.

다른 테스트 케이스간에 종속성이있는 경우 모든 테스트 케이스가 병렬로 실행되므로 오 탐지가 발생할 수 있습니다. 어쨌든 상호 의존적 인 테스트를해서는 안됩니다.


0

또 다른 선택 : 새로운 병렬 junit 러너 및 maven 플러그인 인 Punner. 코드를 변경할 필요없이 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는 테스트 방법을 병렬로 실행할 수 있으며 테스트 출력을 개별적으로 깨끗하게 유지할 수 있습니다.

Punner는 다음과 같이 mvn 콘솔 출력을 줄입니다.

[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는 확실한 호환 출력을 생성하며, 보고서 디렉토리에서 원시 로그 데이터 및 마크 다운 형식 보고서를 가져올 수도 있습니다.

  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는 제 개인 프로젝트입니다. 저는 IPC 프레임 워크, 세분화 된 잠금, 저널 서비스, 분산 워크 플로 엔진 등과 같은 다른 프로젝트의 단위 테스트 단계를 가속화하기 위해 Punner를 작성했습니다. 대기 시간을 많이 절약했습니다.

Punner는 아직 일부 고급 기능을 지원하지 않습니다. 시도해보고 피드백을 주시면 매우 기쁩니다.


-3

테스트를 1 분 안에 TestNg 테스트로 변경할 수 있습니다 (가져 오기만 변경하면 됨). TestNG는 병렬 테스트에서 최고입니다.


-3

컴퓨팅 그리드에 테스트를 배포 할 수있는 Gridgain 을 사용해 볼 수 있습니다.


1
GridGain 솔루션을 사용해 보았고 두 가지 주요 문제가있었습니다. 첫째, GridGain이 사용하는 모든 것 (예 : Spring 및 많은 Apache Commons 항목)을 그리드 태스크의 클래스 경로에서 제외하도록 GridGain에 알려야합니다. 둘째, 네트워크 클래스 로딩은 훌륭한 아이디어이지만 클래스 경로를 검색하려는 라이브러리에는 작동하지 않습니다. 예 : Spring
Graham Lea
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.