การทดสอบ JUnit พร้อมจำนวนการทดสอบแบบไดนามิก


95

ในโครงการของเราฉันมีการทดสอบJUnitหลายครั้งเช่นนำทุกไฟล์จากไดเร็กทอรีและรันการทดสอบ หากฉันใช้testEveryFileInDirectoryวิธีการในTestCaseนี้จะแสดงเป็นเพียงการทดสอบเดียวที่อาจล้มเหลวหรือประสบความสำเร็จ แต่ฉันสนใจผลลัพธ์ในแต่ละไฟล์ ฉันจะเขียนTestCase/ TestSuiteเพื่อให้แต่ละไฟล์แสดงเป็นการทดสอบแยกกันเช่นใน TestRunner แบบกราฟิกของ Eclipse ได้อย่างไร (การเข้ารหัสวิธีการทดสอบที่ชัดเจนสำหรับแต่ละไฟล์ไม่ใช่ตัวเลือก)

เปรียบเทียบยังคำถามParameterizedTest ที่มีชื่อใน Eclipse TestRunner


คำตอบ:


102

ดูที่Parameterized Testsใน JUnit 4

อันที่จริงฉันทำไม่กี่วันที่ผ่านมา ฉันจะพยายามอธิบาย ...

ขั้นแรกให้สร้างคลาสทดสอบของคุณตามปกติในขณะที่คุณทดสอบด้วยไฟล์อินพุตเดียว ตกแต่งชั้นเรียนของคุณด้วย:

@RunWith(Parameterized.class)

สร้างตัวสร้างหนึ่งตัวที่รับอินพุตที่จะเปลี่ยนแปลงในทุก ๆ การเรียกทดสอบ (ในกรณีนี้อาจเป็นไฟล์เอง)

จากนั้นสร้างเมธอดแบบคงที่ซึ่งจะส่งคืนCollectionอาร์เรย์ แต่ละอาร์เรย์ในคอลเล็กชันจะมีอาร์กิวเมนต์อินพุตสำหรับตัวสร้างคลาสของคุณเช่นไฟล์ ตกแต่งวิธีนี้ด้วย:

@Parameters

นี่คือคลาสตัวอย่าง

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

ตรวจสอบตัวอย่างนี้ด้วย


1
ขอบคุณ! วิธี JUnit 4 ดีกว่าวิธี JUnit 3 ที่ให้ไว้ในคำตอบอื่นเนื่องจาก JUnit 3 ทำให้นักวิ่งทดสอบคราสสับสนและด้วยวิธี JUnit 4 คุณสามารถดำเนินการทดสอบใหม่ได้ ฯลฯ ฉันสงสัยว่าฉันจะให้คราสแสดงได้อย่างไร ชื่อสำหรับการทดสอบ - แสดงเฉพาะ [0], [1] ฯลฯ
Hans-Peter Störr

@hstoerr ดูเหมือนว่านี่จะอยู่ใน JUnit รุ่นถัดไป :-) github.com/KentBeck/junit/commit/…
rescdsk

คุณจะแปลงค่านี้ได้อย่างไรหากคุณต้องการให้แต่ละการรัน [ด้วยชุดข้อมูลที่แตกต่างกัน] แก้ไขชื่อของการทดสอบ [เช่นไฟล์ Path1 จะถูกทดสอบเป็น: test1Path1, test2Path?
พระ

^ ลิงก์อัปเดต: 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());
    }

}

11

การทดสอบพารามิเตอร์ Junit 5

การทดสอบพารามิเตอร์JUnit 5สนับสนุนสิ่งนี้โดยอนุญาตให้ใช้วิธีการเป็นแหล่งข้อมูล :

@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นอกจากนี้ยังสนับสนุนนี้ผ่านความคิดของการที่DynamicTestซึ่งจะถูกสร้างขึ้นในโดยใช้วิธีการวิธีการแบบคงที่@TestFactorydynamicTest

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

การทดสอบใน IDE ของคุณ (IntelliJ ที่นี่) จะแสดงดังนี้:

เอาต์พุตใน IntelliJ


3

ควรเป็นไปได้ใน JUnit 3 โดยการสืบทอดTestSuiteและแทนที่tests()เมธอดในการแสดงรายการไฟล์และสำหรับแต่ละอินสแตนซ์ของคลาสย่อยTestCaseที่ใช้ชื่อไฟล์เป็นพารามิเตอร์ตัวสร้างและมีวิธีทดสอบที่ทดสอบไฟล์ที่กำหนดในตัวสร้าง

ใน JUnit 4 มันอาจจะง่ายกว่านี้


2

คุณสามารถพิจารณาใช้ไลบรารี JUnitParams ได้ดังนั้นคุณจะมีตัวเลือกอื่น ๆ (ที่สะอาดกว่า):

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

ท่านสามารถดูรายละเอียดเพิ่มเติมตัวอย่างของการใช้งานที่นี่

นอกจากนี้เกี่ยวกับ JUnitParams เหตุใดการเขียนการทดสอบแบบกำหนดพารามิเตอร์จึงง่ายและอ่านง่ายขึ้น :

โครงการ JUnitParams เพิ่มตัววิ่งใหม่ให้กับ JUnit และให้การทดสอบพารามิเตอร์ที่ง่ายและอ่านได้สำหรับ JUnit> = 4.6

ความแตกต่างหลักของนักวิ่ง JUnit Parametrised มาตรฐาน:

  • ชัดเจนมากขึ้น - พารามิเตอร์อยู่ในพารามิเตอร์วิธีการทดสอบไม่ใช่ฟิลด์คลาส
  • รหัสน้อย - คุณไม่จำเป็นต้องมีตัวสร้างเพื่อตั้งค่าพารามิเตอร์
  • คุณสามารถผสม parametrised กับวิธีการที่ไม่ใช่ parametrised ในคลาสเดียว
  • พารามิเตอร์สามารถส่งผ่านเป็นสตริง CSV หรือจากคลาสผู้ให้บริการพารามิเตอร์
  • คลาสผู้ให้บริการพารามิเตอร์สามารถมีพารามิเตอร์ที่จัดเตรียมเมธอดได้มากเท่าที่คุณต้องการเพื่อให้คุณสามารถจัดกลุ่มกรณีต่างๆได้
  • คุณสามารถมีวิธีทดสอบที่ให้พารามิเตอร์ (ไม่มีคลาสหรือสถิตภายนอกอีกต่อไป)
  • คุณสามารถดูค่าพารามิเตอร์ที่แท้จริงใน IDE ของคุณ (ใน Parametrised ของ JUnit เป็นพารามิเตอร์ที่ต่อเนื่องกันเท่านั้น)

1

หาก TestNG เป็นตัวเลือกที่คุณสามารถใช้พารามิเตอร์กับ DataProviders

การทดสอบไฟล์แต่ละไฟล์จะมีผลลัพธ์ที่แสดงในรายงานแบบข้อความหรือ UI ปลั๊กอิน TestNG ของ Eclipse จำนวนการทดสอบทั้งหมดที่ดำเนินการจะนับแต่ละไฟล์ของคุณทีละไฟล์

พฤติกรรมนี้แตกต่างจาก JUnit Theoriesซึ่งผลลัพธ์ทั้งหมดจะรวมเป็นหนึ่งเดียวภายใต้รายการ "ทฤษฎี" และนับเป็น 1 การทดสอบเท่านั้น หากคุณต้องการการรายงานผลแยกจากกันใน JUnit คุณสามารถลองทดสอบ Parameterized

ทดสอบและอินพุต

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

ตัวอย่างผลลัพธ์

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

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

ฉันไม่รู้เกี่ยวกับทฤษฎี แต่การทดสอบพารามิเตอร์ใน JUnit จะแสดงแยกกันในคราสไม่รวมกันเป็นก้อน
Hans-Peter Störr

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.