【问题标题】:JUnit test with dynamic number of tests具有动态测试数量的 JUnit 测试
【发布时间】:2010-09-26 09:44:58
【问题描述】:

在我们的项目中,我有几个 JUnit 测试,例如从目录中获取每个文件并对其运行测试。如果我在TestCase 中实现testEveryFileInDirectory 方法,这将显示为只有一个可能失败或成功的测试。但我对每个单独文件的结果感兴趣。如何编写 TestCase / TestSuite 以便每个文件显示为单独的测试,例如在 Eclipse 的图形化 TestRunner 中? (不能为每个文件编写明确的测试方法。)

比较问题ParameterizedTest with a name in Eclipse Testrunner

【问题讨论】:

标签: java unit-testing junit parameterized-unit-test


【解决方案1】:

在 JUnit 3 中应该可以通过从 TestSuite 继承并覆盖 tests() 方法来列出文件并为每个返回 TestCase 的子类的实例,该实例将文件名作为构造函数参数并进行测试测试构造函数中给出的文件的方法。

在 JUnit 4 中可能会更容易。

【讨论】:

    【解决方案2】:

    看看 JUnit 4 中的 Parameterized Tests

    实际上我几天前就这样做了。我会尽力解释...

    首先正常构建您的测试类,因为您只使用一个输入文件进行测试。 用以下方式装饰你的班级:

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

    也可以查看example

    【讨论】:

    • 谢谢! JUnit 4 方法优于另一个答案中给出的 JUnit 3 方法,因为 JUnit 3 混淆了 eclipse 测试运行器,并且使用 JUnit 4 方法您可以重新执行测试等。我只是想知道如何让 eclipse 显示测试名称 - 它只显示 [0]、[1] 等。
    • @hstoerr,看起来这将出现在 JUnit 的下一个版本中 :-) github.com/KentBeck/junit/commit/…
    • 如果您希望每次运行 [使用不同的数据组合] 修改这些测试运行的名称,您将如何转换它? [IE。 Path1 文件将被测试为:test1Path1, test2Path?
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      如果 TestNG 是一个选项,您可以使用Parameters with DataProviders

      每个单独文件的测试都将在基于文本的报告或 Eclipse 的 TestNG 插件 UI 中显示其结果。运行的总测试数将单独计算每个文件。

      此行为与 JUnit Theories 不同,其中所有结果都集中在一个“理论”条目下,仅计为 1 次测试。如果你想在 JUnit 中单独报告结果,你可以试试Parameterized Tests

      测试和输入

      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 中的参数化测试在 eclipse 中是单独显示的,而不是放在一起。
      【解决方案5】:

      您可以考虑使用JUnitParams library,这样您就有更多(更简洁)的选择:

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

      你可以看到更多samples of usage here

      另外about JUnitParams, why writting parameterized tests with it is easier and more readable:

      JUnitParams 项目为 JUnit 添加了一个新的运行器并提供了很多 JUnit >=4.6 的更简单易读的参数化测试。

      与标准 JUnit 参数化运行器的主要区别:

      • 更明确 - 参数在测试方法参数中,而不是类字段中
      • 更少的代码——你不需要构造函数来设置参数
      • 您可以在一个类中混合使用参数化方法和非参数化方法
      • 参数可以作为 CSV 字符串或从参数提供程序类传递
      • 参数提供者类可以有尽可能多的参数提供方法,以便您可以对不同的情况进行分组
      • 您可以拥有一个提供参数的测试方法(不再需要外部类或静态)
      • 您可以在 IDE 中看到实际的参数值(在 JUnit 的参数化中,它只是连续的参数数量)

      【讨论】:

        【解决方案6】:

        我遇到了类似的问题,最终编写了一个简单的 JUnit 4 运行程序,允许 med 动态生成测试。

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

        【讨论】:

          【解决方案7】:

          Junit 5 参数化测试

          JUnit 5 参数化测试通过允许使用method as data source 来支持这一点:

          @ParameterizedTest
          @MethodSource("fileProvider")
          void testFile(File f) {
              // Your test comes here
          }
          
          static Stream<File> fileProvider() {
              return Arrays.asList(new File(".").list()).stream();
          }
          

          JUnit 5 动态测试

          JUnit 5 还通过DynamicTest 的概念支持这一点,该概念将通过静态方法dynamicTest@TestFactory 中生成。

          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)中运行的测试将显示如下:

          【讨论】:

            猜你喜欢
            • 2011-03-22
            • 1970-01-01
            • 2020-06-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多