Uji JUnit dengan sejumlah pengujian dinamis

95

Dalam proyek kami, saya memiliki beberapa tes JUnit yang misalnya mengambil setiap file dari direktori dan menjalankan tes padanya. Jika saya menerapkan testEveryFileInDirectorymetode TestCaseini muncul sebagai hanya satu tes yang mungkin gagal atau berhasil. Tapi saya tertarik dengan hasil pada setiap file. Bagaimana saya bisa menulis TestCase/ TestSuitesedemikian sehingga setiap file muncul sebagai tes terpisah misalnya dalam TestRunner grafis dari Eclipse? (Mengkodekan metode pengujian eksplisit untuk setiap file bukanlah suatu pilihan.)

Bandingkan juga pertanyaan ParameterizedTest dengan nama di Eclipse Testrunner .

Hans-Peter Störr
sumber

Jawaban:

102

Lihatlah Tes Parameterized di JUnit 4.

Sebenarnya saya melakukan ini beberapa hari yang lalu. Saya akan mencoba menjelaskan ...

Pertama-tama, buat kelas pengujian Anda secara normal, seperti Anda yang hanya menguji dengan satu file masukan. Hiasi kelas Anda dengan:

@RunWith(Parameterized.class)

Buat satu konstruktor yang mengambil input yang akan berubah di setiap panggilan uji (dalam hal ini mungkin file itu sendiri)

Kemudian, buat metode statis yang akan mengembalikan Collectionarray. Setiap larik dalam koleksi akan berisi argumen input untuk konstruktor kelas Anda, misalnya file. Hiasi metode ini dengan:

@Parameters

Ini contoh kelasnya.

@RunWith(Parameterized.class)
public class ParameterizedTest {

    private File file;

    public ParameterizedTest(File file) {
        this.file = file;
    }

    @Test
    public void test1() throws Exception {  }

    @Test
    public void test2() throws Exception {  }

    @Parameters
    public static Collection<Object[]> data() {
        // load the files as you want
        Object[] fileArg1 = new Object[] { new File("path1") };
        Object[] fileArg2 = new Object[] { new File("path2") };

        Collection<Object[]> data = new ArrayList<Object[]>();
        data.add(fileArg1);
        data.add(fileArg2);
        return data;
    }
}

Periksa juga contoh ini

bruno conde
sumber
1
Terima kasih! Metode JUnit 4 lebih baik daripada Metode JUnit 3 yang diberikan dalam jawaban lain, karena JUnit 3 membingungkan pelari pengujian gerhana dan dengan Metode JUnit 4 Anda dapat menjalankan ulang pengujian, dll. Saya hanya bertanya-tanya bagaimana saya dapat menampilkan gerhana nama untuk pengujian - ini hanya menampilkan [0], [1] dll.
Hans-Peter Störr
@hstoerr, Sepertinya ini akan ada di rilis JUnit berikutnya :-) github.com/KentBeck/junit/commit/…
rescdsk
Bagaimana Anda akan mengubah ini jika Anda ingin setiap proses [dengan kombinasi data yang berbeda] untuk mengubah nama pengujian ini? [Yaitu file Path1 akan diuji sebagai: test1Path1, test2Path?
monksy
^ Tautan yang diperbarui: github.com/junit-team/junit4/commit/…
Alexander Udalov
27

JUnit 3

public class XTest extends TestCase {

    public File file;

    public XTest(File file) {
        super(file.toString());
        this.file = file;
    }

    public void testX() {
        fail("Failed: " + file);
    }

}

public class XTestSuite extends TestSuite {

    public static Test suite() {
        TestSuite suite = new TestSuite("XTestSuite");
        File[] files = new File(".").listFiles();
        for (File file : files) {
            suite.addTest(new XTest(file));
        }
        return suite;
    }

}

JUnit 4

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class TestY {

    @Parameters
    public static Collection<Object[]> getFiles() {
        Collection<Object[]> params = new ArrayList<Object[]>();
        for (File f : new File(".").listFiles()) {
            Object[] arr = new Object[] { f };
            params.add(arr);
        }
        return params;
    }

    private File file;

    public TestY(File file) {
        this.file = file;
    }

    @Test
    public void testY() {
        fail(file.toString());
    }

}
McDowell
sumber
11

Junit 5 Tes Parameter

Tes berparameter JUnit 5 mendukung ini dengan mengizinkan penggunaan metode sebagai sumber data :

@ParameterizedTest
@MethodSource("fileProvider")
void testFile(File f) {
    // Your test comes here
}

static Stream<File> fileProvider() {
    return Arrays.asList(new File(".").list()).stream();
}

JUnit 5 DynamicTests

JUnit 5 juga mendukung hal ini melalui gagasan a DynamicTest, yang akan dihasilkan dalam a @TestFactory, dengan menggunakan metode statis dynamicTest.

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.stream.Stream;

@TestFactory
public Stream<DynamicTest> testFiles() {
    return Arrays.asList(new File(".").list())
            .stream()
            .map((file) -> dynamicTest(
                    "Test for file: " + file,
                    () -> { /* Your test comes here */ }));
}

Tes yang dijalankan di IDE Anda (IntelliJ di sini) akan ditampilkan seperti ini:

Output di IntelliJ

avandeursen
sumber
3

Harus dimungkinkan di JUnit 3 dengan mewarisi dari TestSuitedan menimpa tests()metode ke daftar file dan untuk setiap mengembalikan sebuah instance dari subkelas TestCaseyang mengambil nama file sebagai parameter konstruktor dan memiliki metode pengujian yang menguji file yang diberikan dalam konstruktor.

Di JUnit 4 mungkin akan lebih mudah.

Michael Borgwardt
sumber
2

Anda dapat mempertimbangkan untuk menggunakan perpustakaan JUnitParams , jadi Anda akan memiliki beberapa opsi (lebih bersih):

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test1(File file) throws Exception {  }

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test2(File file) throws Exception {  }

    public static File[] data() {
        return new File[] { new File("path1"), new File("path2") };
    }
}

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test1(String path) throws Exception {
        File file = new File(path);
    }

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test2(String path) throws Exception {
        File file = new File(path);
    }
}

Anda dapat melihat lebih banyak contoh penggunaan di sini .

Selain itu tentang JUnitParams, mengapa menulis pengujian berparameter dengannya lebih mudah dan lebih terbaca :

Proyek JUnitParams menambahkan runner baru ke JUnit dan menyediakan pengujian parametrised yang lebih mudah dan terbaca untuk JUnit> = 4.6.

Perbedaan utama dengan pelari JUnit Parametrised standar:

  • lebih eksplisit - params ada dalam parameter metode pengujian, bukan bidang kelas
  • lebih sedikit kode - Anda tidak memerlukan konstruktor untuk menyiapkan parameter
  • Anda bisa mencampur parametrised dengan metode non-parametrised dalam satu kelas
  • params dapat dikirimkan sebagai string CSV atau dari kelas penyedia parameter
  • kelas penyedia parameter dapat memiliki metode penyedia parameter sebanyak yang Anda inginkan, sehingga Anda dapat mengelompokkan kasus yang berbeda
  • Anda dapat memiliki metode pengujian yang menyediakan parameter (tidak ada kelas eksternal atau statika lagi)
  • Anda dapat melihat nilai parameter aktual di IDE Anda (di JUnit's Parametrised, hanya ada jumlah parameter yang berurutan)
falsarella
sumber
1

Jika TestNG adalah sebuah opsi, Anda dapat menggunakan Parameter dengan DataProviders .

Setiap pengujian file akan menampilkan hasilnya dalam laporan berbasis teks atau UI plugin TestNG Eclipse. Jumlah total pengujian yang dijalankan akan menghitung setiap file Anda satu per satu.

Perilaku ini berbeda dengan Teori JUnit , di mana semua hasil disatukan dalam satu entri "teori" dan hanya dihitung sebagai 1 tes. Jika Anda ingin pelaporan hasil terpisah di JUnit, Anda dapat mencoba Pengujian Parameter .

Tes dan masukan

public class FileTest {

    @DataProvider(name="files")
    public File[][] getFiles(){
        return new File[][] {
            { new File("file1") },
            { new File("file2") }
        };
        // or scan a directory
    }

    @Test(dataProvider="files")
    public void testFile(File file){
        //run tests on file
    }
}

Contoh keluaran

PASSED: testFile(file1)
PASSED: testFile(file2)

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================
Ben Hutchison
sumber
Saya tidak tahu tentang teori, tetapi pengujian berparameter di JUnit ditampilkan secara terpisah di gerhana, tidak disatukan.
Hans-Peter Störr