Junit: pemisahan tes integrasi dan tes Unit

126

Saya telah mewarisi banyak tes Junit, tetapi tes ini (selain sebagian besar tidak berfungsi) adalah campuran dari tes unit aktual dan tes integrasi (membutuhkan sistem eksternal, db dll).

Jadi saya mencoba memikirkan cara untuk benar-benar memisahkan mereka, sehingga saya dapat menjalankan tes unit dengan baik dan cepat dan tes integrasi setelah itu.

Opsinya adalah ..

  1. Membagi mereka menjadi direktori yang terpisah.

  2. Pindah ke Junit4 (dari v3) dan beri catatan pada kelas untuk memisahkannya.

  3. Gunakan konvensi penamaan file untuk memberi tahu apa kelasnya, yaitu AdapterATest dan AdapterAIntergrationTest.

3 memiliki masalah bahwa Eclipse memiliki opsi untuk "Menjalankan semua tes dalam proyek / paket atau folder yang dipilih". Jadi akan sangat sulit untuk hanya menjalankan tes integrasi.

2: menjalankan risiko bahwa pengembang mungkin mulai menulis tes integrasi di kelas unit test dan itu hanya menjadi berantakan.

1: Sepertinya solusi yang paling rapi, tetapi nyali saya mengatakan harus ada solusi yang lebih baik di luar sana.

Jadi itu pertanyaan saya, bagaimana Anda banyak memecah tes integrasi dan tes unit yang tepat?

jeff porter
sumber
Saya hanya ingin mengucapkan terima kasih atas masukan Anda, saya tahu ini adalah pertanyaan subjektif, dan bukan satu jawaban yang benar. Tetapi Anda telah membantu saya menyadari bahwa tidak ada pilihan lain selain yang saya daftarkan. Saya pikir saya akan pergi dengan struktur direktori untuk saat ini dan pindah ke JUnit4, meskipun belum menggunakan anotasi untuk memisahkan mereka dulu.
jeff porter

Jawaban:

10

Saat ini saya menggunakan direktori terpisah karena kebijakan organisasi (dan warisan Junit 3) tapi saya sendiri ingin beralih ke anotasi sekarang saya di Junit 4.

Saya tidak akan terlalu khawatir tentang pengembang yang menempatkan tes integrasi di kelas uji unit Anda - tambahkan aturan dalam standar pengkodean Anda jika perlu.

Saya tertarik untuk mengetahui solusi apa yang mungkin ada selain dari penjelasan atau memisahkan kelas secara fisik ..

Steven Mackenzie
sumber
145

Anda dapat membaginya dengan sangat mudah menggunakan kategori JUnit dan Maven.

Ini ditunjukkan sangat, sangat singkat di bawah ini dengan pemisahan unit dan tes integrasi.

Tentukan Antarmuka Penanda

Langkah pertama dalam mengelompokkan tes menggunakan kategori adalah membuat antarmuka penanda.

Antarmuka ini akan digunakan untuk menandai semua tes yang ingin Anda jalankan sebagai tes integrasi.

public interface IntegrationTest {}

Tandai kelas tes Anda

Tambahkan anotasi kategori ke bagian atas kelas tes Anda. Dibutuhkan nama antarmuka baru Anda.

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest{
  @Test
  public void longRunningServiceTest() throws Exception {
  }
}

Konfigurasikan Tes Unit Maven

Keindahan dari solusi ini adalah tidak ada yang benar-benar berubah untuk sisi pengujian unit.

Kami cukup menambahkan beberapa konfigurasi ke plugin maven surefire untuk membuatnya mengabaikan semua tes integrasi.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

Ketika Anda melakukan tes bersih mvn hanya tes unit tanpa tanda Anda akan berjalan.

Konfigurasikan Tes Integrasi Maven

Sekali lagi konfigurasi untuk ini sangat sederhana.

Untuk menjalankan hanya tes integrasi, gunakan ini:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

Jika Anda membungkus ini dalam profil dengan id IT, Anda hanya dapat menjalankan tes cepat menggunakan mvn clean install. Untuk menjalankan hanya tes integrasi / lambat, gunakan mvn clean install -P IT.

Tetapi paling sering, Anda ingin menjalankan tes cepat secara default dan semua tes dengan -P IT. Jika itu masalahnya, maka Anda harus menggunakan trik:

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Seperti yang Anda lihat, saya mengecualikan tes yang dijelaskan dengan java.io.Serializable. Ini diperlukan karena profil akan mewarisi konfigurasi default plugin Surefire, jadi meskipun Anda mengatakan <excludedGroups/>atau <excludedGroups></excludedGroups>, nilainya com.test.annotation.type.IntegrationTestakan digunakan.

Anda juga tidak dapat menggunakan nonekarena harus berupa antarmuka di classpath (Maven akan memeriksa ini).

Catatan:

  • Ketergantungan ke surefire-junit47hanya diperlukan ketika Maven tidak beralih ke pelari JUnit 4 secara otomatis. Menggunakan elemen groupsatau excludedGroupsharus memicu sakelar. Lihat di sini .
  • Sebagian besar kode di atas diambil dari dokumentasi untuk plugin Maven Failsafe. Lihat bagian "Menggunakan Kategori JUnit" di halaman ini .
  • Selama pengujian saya, saya menemukan bahwa ini bahkan berfungsi ketika Anda menggunakan @RunWith()anotasi untuk menjalankan suite atau tes berbasis pegas.
John Dobie
sumber
18
Saya pikir ada kesalahan dalam fragmen pom.xml terakhir Anda. Anda menempelkan cuplikan yang sama dengan untuk fase "tes". masih mengecualikan tes integrasi dan juga tidak terikat pada fase pakar.
Alex
1
Memang, fragmen pom terakhir adalah kesalahan copy & paste. Itu harus menunjukkan maven -ailsafe-plugin.
Paulo Merson
2
Jadi apa yang seharusnya menjadi xml kedua? : O
Liv
Anda tidak harus menggunakan trik (sulap terakhir dengan Serializable) jika Anda menggunakan profil Maven default
user831217
Ini harus benar-benar menjadi jawaban yang diterima karena ini sebenarnya merupakan solusi untuk pertanyaan dan bukan debat filosofis tentang di mana menempatkan tes yang berbeda.
Bwvolleyball
40

Kami menggunakan Maven Surefire Plugin untuk menjalankan tes unit dan Maven Failsafe Plugin untuk menjalankan tes integrasi. Tes unit mengikuti **/Test*.java **/*Test.java **/*TestCase.javakonvensi penamaan, tes integrasi - **/IT*.java **/*IT.java **/*ITCase.java. Jadi itu sebenarnya pilihan Anda nomor tiga.

Dalam beberapa proyek kami menggunakan TestNG dan menentukan kelompok uji yang berbeda untuk tes integrasi / unit, tetapi ini mungkin tidak cocok untuk Anda.

lexicore
sumber
1
+1 untuk pakar + pasti + gagal + kombo junit. Saya tidak menyadari failafe akan menjalankan "IT *" secara otomatis. Manis.
PapaFreud
13

Saya akan naik ke Junit4 hanya untuk memilikinya :)

Anda dapat memisahkannya menjadi beberapa ruang uji. Saya tidak tahu bagaimana mereka diorganisasikan dalam Junit3 tetapi seharusnya mudah di Junit4 hanya untuk membangun suite tes dan menempatkan semua unit test nyata di salah satunya dan kemudian menggunakan suite kedua untuk tes integrasi.

Sekarang tentukan konfigurasi run untuk kedua suite di eclipse dan Anda dapat dengan mudah menjalankan satu suite. Suite ini juga dapat diluncurkan dari proses otomatis yang memungkinkan Anda menjalankan tes unit setiap kali sumber berubah dan mungkin tes integrasi (jika benar-benar besar) hanya sekali sehari atau sekali dalam satu jam.

Janusz
sumber
9

Menggunakan anotasi pegas IfProfileValue memungkinkan untuk mencapai hal ini tanpa memerlukan plugin atau konfigurasi.

Buat anotasi kelas atau metode pengujian integrasi menggunakan IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest{
    @Test
    public void longRunningServiceTest() throws Exception {
    }
} 

Untuk menjalankan menggunakan unit test saja:

mvn clean test

Untuk menjalankan menggunakan tes integrasi dan tes unit:

mvn clean test -Dtest-groups=integration

Juga, "Jalankan semua tes" dalam IDE hanya akan menjalankan tes unit. Tambahkan -Dtest-groups=integrationke argumen VM untuk menjalankan tes integrasi dan unit.

Mit Mehta
sumber
Pendekatan ini bagus dan sederhana, tetapi masalah yang saya temukan adalah bahwa secara default saya ingin menjalankan semua tes (termasuk tes integrasi). Itu tidak mungkin dengan pendekatan ini, bukan?
csalazar
6

Tidak ada satu jawaban yang benar. Seperti yang sudah Anda jelaskan, ada beberapa cara untuk melakukannya yang akan berhasil. Saya telah melakukan skema penamaan file dan memecah hal-hal menjadi direktori yang berbeda.

Kedengarannya seperti memecah hal-hal menjadi direktori yang berbeda mungkin bekerja lebih baik untuk Anda, dan itu tampak sedikit lebih jelas bagi saya, jadi saya akan condong ke arah itu.

Saya tidak berpikir saya akan mencoba anotasi karena itu tampaknya lebih halus bagi saya. Apakah Anda benar-benar ingin kedua jenis tes ini digabungkan menjadi satu dalam file yang sama? Saya tidak akan.

ndp
sumber