【问题标题】:How to parameterize junit Test Suite如何参数化junit测试套件
【发布时间】:2014-02-26 19:46:56
【问题描述】:

是否可以在 junit 4 中对 TestSuite 进行参数化?

为了将一个类声明为测试套件,我需要注解@RunWith(Suite.class),但也需要相同的注解来将测试声明为参数化:@RunWith(Parameterized.class),所以我不能将两者都添加到同一个类中。

我在这个网站上发现了一个类似的question,但并没有多大帮助。到目前为止,我找到的所有示例都说明了如何参数化简单的单元测试,而不是完整的测试套件。

【问题讨论】:

    标签: java junit4 junit-runner


    【解决方案1】:

    我相信基本答案是否定的,因为正如您所说,@RunsWith 只接受一个参数。我在如何处理这种情况下找到了blog posting that got a bit creative

    我们不使用参数化测试,但您可以像我们一样创建一个单独的套件,只列出测试类,参数化测试可以是其中的一部分。我修改了我们的测试套件,在套件的一部分中包含了一个参数化的测试类,它运行良好。我们创建了如下所示的套件,其中 PrimeNumberCheckerTest 是我从网络上提取的一个简单的。

    package com.jda.portfolio.api.rest.server;
    
    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;
    import org.junit.runners.Suite.SuiteClasses;
    
    @RunWith(Suite.class)
    @SuiteClasses({  com.mycompany.api.rest.server.resource.TestCartResourceJava.class, 
                     com.mycompany.api.rest.server.resource.TestCustomerResource.class,
                     com.mycompany.api.rest.server.resource.TestWizardProfileResource.class,
                     com.mycompany.api.rest.server.interceptor.TestBaseSearchInterceptor.class, 
                     com.mycompany.api.rest.server.resource.TestQueryParameters.class, 
                     com.mycompany.api.rest.server.expression.TestCartExpressionGenerator.class, 
                     com.mycompany.api.rest.server.expression.TestPreferenceExpressionGenerator.class, 
                     com.mycompany.api.rest.server.PrimeNumberCheckerTest.class, 
                     })
    public class AllTests {}
    

    这是参数化测试用例的来源;

    package com.jda.portfolio.api.rest.server:
    
    import static org.junit.Assert.*;
    import java.util.Arrays;
    import java.util.Collection;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Suite.SuiteClasses;
    
    @RunWith(Parameterized.class)
    @SuiteClasses({PrimeNumberCheckerTest.class})
    public class PrimeNumberCheckerTest {
      private Integer inputNumber;
      private Boolean expectedResult;
      private PrimeNumberChecker primeNumberChecker;
    
      @Before
      public void initialize() {
         primeNumberChecker = new PrimeNumberChecker();
      }
    
      // Each parameter should be placed as an argument here
      // Every time runner triggers, it will pass the arguments
      // from parameters we defined in primeNumbers() method
      public PrimeNumberCheckerTest(Integer inputNumber, 
         Boolean expectedResult) {
         this.inputNumber = inputNumber;
         this.expectedResult = expectedResult;
      }
    
      @Parameterized.Parameters
      public static Collection primeNumbers() {
         return Arrays.asList(new Object[][] {
            { 2, true },
            { 6, false },
            { 19, true },
            { 22, false },
            { 23, true }
         });
      }
    
      // This test will run five times since we have as many parameters defined
      @Test
      public void testPrimeNumberChecker() {
         System.out.println("Parameterized Number is : " + inputNumber);
         assertEquals(expectedResult, 
         primeNumberChecker.validate(inputNumber));
      }
    

    【讨论】:

    • -1 因为我认为你没有抓住重点。 Sergio 想要参数化套件本身,而不仅仅是执行单个参数化测试
    【解决方案2】:

    我能够参数化测试套件并在套件的测试类成员中使用其数据,如下所示:

    在 JUTsuite 中:

    @RunWith(Suite.class)
    @Suite.SuiteClasses({ 
        JUT_test1.class,
    })
    
    public class JUTSuite{  
        // Declare all variables/objects you want to share with the test classes, e.g.
        protected static List<Fx> globalFxs;
        // This is the data list we'll use as parameters
        protected static List<Dx> globalDxs;
    
        @Parameters
        public static Collection<Object[]> data(){
            // Instantiate object list for parameters.  
            // Note: you must do it here and not in, say, @BeforeClass setup()
            // e.g.
            globalDxs=new ArrayList<Dx>(serverObj.values());
    
            Collection<Object[]> rows=new ArrayList<Object[]>();
            for(Dx d:globalDxs) {
                rows.add(new Object[]{d});
            }
            return rows;
        }
    
        @BeforeClass
        public static void setUp() throws Exception {
            // Instantiate/initialize all suite variables/objects to be shares with test classes
            // e.g. globalFxs=new ArrayList<Fx>();
        }
    
        @AfterClass
        public static void tearDown() throws Exception {
            // Clean up....
        }
    }
    

    接下来,在测试类中:

    @RunWith(Parameterized.class)
    public class JUT_test1 {
        // declare local names (if desired) for suite-wide variable/objects 
        // e.g. 
        private static List<Fx> globalFxs;
    
        // This is the test parameter:      
        private Dx d;
    
        public JUT_test1(Dx d){
            this.d=d;
        }
    
        @Parameters
        public static Collection<Object[]> data(){
        // Note: we're calling the suite's data() method which has already executed.
            return JUTSuite.data();
        }
    
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
        // (If desired)initialize local variables by referencing suite variables.
        // e.g.globalFxs=JUTSuite.globalFxs;
        }
    }
    

    【讨论】:

    • 你能解释一下JUT_KB_integrity是构造函数还是setter?
    • 没关系,我更正了。谢谢你的详细解释。
    【解决方案3】:

    我同意,使用提供的类是不可能的,但是有一些解决方法可以帮助您完成大部分工作,例如 @mikemil 的。

    我花了一些时间扩展 Suite 并委托给 Parameterized,取得了部分成功;可以构建执行您想要的运行器,并且在这两个类中或多或少地为您编写代码。这些类的交互方式(特别是Parameterized#getChildren() 的定义)使得难以扩展或委托给这些类来完成您需要的工作,但是创建一个全新的类而不是扩展ParentRunner 并从其他两个类中提取代码会很容易。

    稍后我会争取更多时间来讨论这个问题。如果您确实在我开始之前构建了一个新的跑步者,请将其发布为答案,我很乐意自己使用它。

    【讨论】:

    • 在此期间您有没有抽出时间这样做,保罗? :-)
    【解决方案4】:

    最好的解决方案是将西装类分开放在一个空白类中。 例如,我将登录作为参数化测试进行测试并穿上西装(用于导航性能测量)

         @RunWith(Suite.class)
    @Suite.SuiteClasses({
                LoginPageTest.class,
                HomePageTests.class})
        public class PerformanceTests {
        }
    

    而LoginPageTest其实是Parameterizedtests

    @RunWith(Parameterized.class)
    public class LoginPageTest
    {...}
    

    【讨论】:

      【解决方案5】:

      正如已经多次声明的那样,不可能使用JUnit 4 提供的运行器参数化测试套件。

      无论如何,我不建议让您的测试类依赖于某些外部提供的状态。如果你想运行一个测试类怎么办?

      我建议您创建单独的测试类@Parameterized 并使用实用程序类来提供参数:

      @RunWith(Suite.class)
      @SuiteClasses({ Test1.class, Test2.class })
      public class TestSuite {
          // suite
      }
      
      @RunWith(Parameterized.class}
      public class Test1 {
          public Test1(Object param1) { /* ... */ }
      
          @Parameters
          public static Collection<Object[]> data() {
              return TestParameters.provideTestData()
          }
      
          @Test
          public void someTest() { /* ... */ }
      }
      
      @RunWith(Parameterized.class}
      public class Test2 {
          public Test2(Object param1) { /* ... */ }
      
          @Parameters
          public static Collection<Object[]> data() {
              return TestParameters.provideTestData()
          }
      
          @Test
          public void someOtherTest() { /* ... */ }
      }
      
      class TestParameters {
          public static Collection<Object[]> provideTestData() {
              Collection<Object[]> data = new ...;
              // build testdata
          return data;
      }
      

      【讨论】:

        【解决方案6】:

        你说得对:SuiteParameterized 都是 Runners,一次只能使用一个 Runner 来运行测试。标准 JUnit 4 不提供组合的 Runner。

        您可以实现自己的 Runner,也可以查看这个提供ParameterizedSuite Runner 的现成库:https://github.com/PeterWippermann/parameterized-suite

        参数化测试套件如下所示:

        @RunWith(ParameterizedSuite.class)
        @SuiteClasses({OneTest.class, TwoTest.class})
        public class MyParameterizedTestSuite {
            @Parameters(name = "Parameters are {0} and {1}")
            public static Object[] params() {
                return new Object[][] {{'A',1}, {'B',2}, {'C',3}};
            }
        

        【讨论】:

          【解决方案7】:

          也许这个答案有帮助:Parameterized unit test suites

          它使用@RunWith(Enclosed.class),似乎解决了问题。

          【讨论】:

            猜你喜欢
            • 2019-01-04
            • 2012-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-10-06
            • 2015-01-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多