development

동적 테스트 수를 사용한 JUnit 테스트

big-blog 2020. 9. 1. 07:52
반응형

동적 테스트 수를 사용한 JUnit 테스트


우리 프로젝트 에는 디렉토리에서 모든 파일을 가져 와서 테스트를 실행하는 여러 JUnit 테스트가 있습니다. testEveryFileInDirectory메서드를 구현하면 TestCase실패하거나 성공할 수있는 하나의 테스트로만 표시됩니다. 하지만 각 개별 파일의 결과에 관심이 있습니다. Eclipse의 그래픽 TestRunner에서 각 파일이 별도의 테스트로 표시되도록 TestCase/를 어떻게 작성할 수 TestSuite있습니까? (각 파일에 대한 명시적인 테스트 방법을 코딩하는 것은 옵션이 아닙니다.)

ParameterizedTest 질문 을 Eclipse Testrunner의 이름과 비교하십시오 .


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

또한,이 체크


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

}

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 also supports this through the notion of a DynamicTest, which is to be generated in a @TestFactory, by means of the static method 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 */ }));
}

The tests run in your IDE (IntelliJ here) will be displayed like this:

Output in IntelliJ


Should be possible in JUnit 3 by inheriting from TestSuite and overriding the tests() method to list the files and for each return an instance of a subclass of TestCase that takes the filename as constructor parameter and has a test method that tests the file given in the constructor.

In JUnit 4 it might be even easier.


You could consider using JUnitParams library, so you would have a few more (cleaner) options:

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

You can see more samples of usage here.

In addition about JUnitParams, why writting parameterized tests with it is easier and more readable:

JUnitParams project adds a new runner to JUnit and provides much easier and readable parametrised tests for JUnit >=4.6.

Main differences to standard JUnit Parametrised runner:

  • more explicit - params are in test method params, not class fields
  • less code - you don't need a constructor to set up parameters
  • you can mix parametrised with non-parametrised methods in one class
  • params can be passed as a CSV string or from a parameters provider class
  • parameters provider class can have as many parameters providing methods as you want, so that you can group different cases
  • you can have a test method that provides parameters (no external classes or statics anymore)
  • you can see actual parameter values in your IDE (in JUnit's Parametrised it's only consecutive numbers of parameters)

If TestNG is an option, you could use Parameters with DataProviders.

Each individual file's test will have its result shown in the text-based report or Eclipse's TestNG plugin UI. The number of total tests run will count each of your files individually.

This behavior differs from JUnit Theories, in which all results are lumped under one "theory" entry and only count as 1 test. If you want separate result reporting in JUnit, you can try Parameterized Tests.

Test and inputs

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

Example output

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

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

I had a similar problem and ended up writing a simple JUnit 4 runner that allows med to dynamically generate tests.

https://github.com/kimble/junit-test-factory

참고URL : https://stackoverflow.com/questions/358802/junit-test-with-dynamic-number-of-tests

반응형