Menjalankan pengujian junit secara paralel dalam build Maven?

110

Saya menggunakan JUnit 4.4 dan Maven dan saya memiliki sejumlah besar pengujian integrasi yang berjalan lama.

Dalam hal memparalelkan rangkaian pengujian, ada beberapa solusi yang memungkinkan saya menjalankan setiap metode pengujian dalam satu kelas pengujian secara paralel. Tetapi semua ini mengharuskan saya mengubah tes dengan satu atau lain cara.

Saya benar-benar berpikir itu akan menjadi solusi yang jauh lebih bersih untuk menjalankan kelas uji X yang berbeda di utas X secara paralel. Saya memiliki ratusan tes jadi saya tidak terlalu peduli tentang memasukkan masing-masing kelas tes.

Apakah ada cara untuk melakukan ini?

krosenvold.dll
sumber

Jawaban:

75

Gunakan plugin 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>
Oleksandr
sumber
12
<parallel> sebenarnya didukung oleh pasti jika Anda menggunakan Junit 4.7 atau lebih baru. panduan pasti
jontejj
42

Dari junit 4.7 sekarang dimungkinkan untuk menjalankan pengujian secara paralel tanpa menggunakan TestNG. Sebenarnya hal itu telah dimungkinkan sejak 4.6, tetapi ada sejumlah perbaikan yang dilakukan di 4.7 yang akan menjadikannya opsi yang layak. Anda juga dapat menjalankan tes paralel dengan pegas, yang dapat Anda baca di sini

krosenvold.dll
sumber
1
Halaman tertaut mengatakan "untuk sebagian besar solusi inti ganda, menjalankan dengan utas paralel saat ini tidak pernah lebih cepat daripada menjalankan non-utas". Apakah masih demikian?
Raedwald
2
Saya akan berpikir bahwa jika tes Anda melakukan IO apa pun, mereka masih akan mendapat manfaat. Misalnya, jika pengujian unit Anda lebih seperti pengujian integrasi dan mengenai database, menjalankan secara paralel akan mempercepatnya.
Dave
@Raedwald Jangan berharap terlalu banyak untuk tes unit non-io-terikat pendek adalah apa yang saya coba katakan. Versi baru yang pasti juga lebih baik / lebih efisien daripada 2.5 yang dijelaskan di pos, jadi Anda mungkin mendapatkan hasil yang sedikit lebih baik.
krosenvold
3
Anda menyatakan itu mungkin, tetapi dapatkah Anda menyertakan tautan ke penjelasan tentang bagaimana? Tautan kedua Anda adalah untuk "dengan musim semi", yang tidak saya minati.
Cory Kendall
@krosenvold link? Saya berjuang untuk menemukan solusi bawaan.
Ilan Biala
10

Terinspirasi oleh percobaan JUnit ParallelComputer pelari Aku telah membangun sendiri ParallelSuite dan ParallelParameterized pelari. Dengan menggunakan pelari ini, seseorang dapat dengan mudah memparalelkan rangkaian pengujian dan pengujian berparameter.

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

Penggunaannya sederhana. Ubah saja nilai anotasi @RunWith ke salah satu kelas Paralel * ini .

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

tempus-fugit menawarkan sesuatu yang serupa, lihat dokumen untuk detailnya. Ini bergantung pada JUnit 4.7 dan Anda cukup menandai pengujian Anda @RunWith(ConcurrentTestRunner).

Bersulang

Toby
sumber
3

Anda dapat melihat pustaka sumber terbuka - Test Load Balancer . Itu persis seperti yang Anda minta - menjalankan kelas pengujian yang berbeda secara paralel. Ini terintegrasi pada tingkat ant-junit sehingga Anda tidak perlu mengubah pengujian Anda. Saya salah satu penulis perpustakaan.

Juga, pikirkan untuk tidak menjalankannya di utas karena Anda mungkin memerlukan kotak pasir tingkat proses. Misalnya, jika Anda mencapai DB dalam pengujian integrasi, Anda tidak ingin satu pengujian gagal karena pengujian lain menambahkan beberapa data di thread berbeda. Seringkali, tes tidak ditulis dengan pemikiran ini.

Akhirnya, bagaimana cara mengatasi masalah ini sampai sekarang?

Pavan
sumber
2

TestNG dapat melakukan itu (ini adalah refleks pertama saya - kemudian saya melihat Anda sudah memiliki banyak testcases).

Untuk JUnit, lihat parallel-junit .

dermawan
sumber
3
Sayangnya ini bukan jawaban atas pertanyaan yang saya ajukan. parallel-junit hanya berjalan dalam satu kelas pengujian. TestNG juga hanya berjalan dalam satu kelas, dan pengujian saya bukanlah pengujian TestNG.
krosenvold
@PlatinumAzure: Saya memperbarui tautan. Saya tidak tahu bagaimana proyek ini dipertahankan. Pertanyaan lain baru-baru ini diajukan untuk mendistribusikan eksekusi tes junit pada beberapa mesin .
philant
2

Anda dapat menjalankan pengujian secara paralel menggunakan ParallelComputer yang disediakan oleh Junit sendiri. Berikut cuplikan kecil untuk Anda mulai.

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

Ini akan membantu saat Anda perlu menjalankan pengujian dari kode karena kode ini tidak memiliki ketergantungan pada Maven atau fitur manajemen build lainnya.

Harap perhatikan bahwa, ini akan menjalankan semua kasus pengujian secara paralel, jika Anda memiliki dependensi di antara kasus pengujian yang berbeda, hal itu dapat menghasilkan positif palsu. Bagaimanapun, Anda HARUS TIDAK melakukan tes yang saling bergantung.

Ashwin Sadeep
sumber
0

Pilihan lain: Punner, pelari junit paralel dan plugin maven baru. Anda tidak perlu mengubah kode Anda, salin ke pom.xml Anda:

<!-- 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 dapat menjalankan metode pengujian secara paralel, dapat menjaga keluaran pengujian secara terpisah dan bersih.

Punner akan mengurangi keluaran konsol mvn Anda, seperti ini:

[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 menghasilkan keluaran yang pasti kompatibel, Anda juga bisa mendapatkan data log mentah dan laporan format penurunan harga dari direktori laporan:

  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 adalah proyek pribadi saya, saya menulis Punner untuk mempercepat fase pengujian unit dari beberapa proyek lain seperti kerangka kerja IPC, penguncian halus, layanan jurnal, mesin alur kerja terdistribusi, dll. Ini menghemat banyak waktu tunggu saya.

Punner belum mendukung beberapa fitur lanjutan. Saya sangat senang jika Anda dapat mencobanya dan memberi saya umpan balik.

Guilin Sun
sumber
-3

Anda dapat mengubah pengujian Anda menjadi pengujian TestNg dalam satu menit (Anda hanya perlu mengubah impor), TestNG adalah yang terbaik dalam pengujian paralel.


sumber
-3

Anda dapat mencoba Gridgain yang memungkinkan Anda menjalankan pengujian Anda di seluruh jaringan komputasi.

Jan Kronquist
sumber
1
Saya telah mencoba solusi GridGain dan mengalami dua masalah utama. Pertama, Anda harus memberitahu GridGain untuk mengecualikan classpath tugas grid Anda apa pun yang juga digunakan GridGain, misalnya Spring dan banyak hal Apache Commons. Kedua, pemuatan kelas jaringan, meskipun merupakan ide cemerlang, tidak berfungsi untuk perpustakaan yang ingin mencari jalur kelas, misalnya Spring
Graham Lea