Java 如何在参数化的情况下运行JUnit SpringJUnit4 ClassRunner?

Java 如何在参数化的情况下运行JUnit SpringJUnit4 ClassRunner?,java,spring,junit,spring-test,Java,Spring,Junit,Spring Test,由于重复的@RunWith注释,以下代码无效: @RunWith(SpringJUnit4ClassRunner.class) @RunWith(Parameterized.class) @SpringApplicationConfiguration(classes = {ApplicationConfigTest.class}) public class ServiceTest { } 但是如何将这两种注释结合使用呢?至少有两种方法可以做到这一点: 跟随 您的测试需要如下所示: @RunW

由于重复的
@RunWith
注释,以下代码无效:

@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(Parameterized.class)
@SpringApplicationConfiguration(classes = {ApplicationConfigTest.class})
public class ServiceTest {
}

但是如何将这两种注释结合使用呢?

至少有两种方法可以做到这一点:

  • 跟随

    您的测试需要如下所示:

     @RunWith(Parameterized.class)
     @ContextConfiguration(classes = {ApplicationConfigTest.class})
     public class ServiceTest {
    
         private TestContextManager testContextManager;
    
         @Before
         public void setUpContext() throws Exception {
             //this is where the magic happens, we actually do "by hand" what the spring runner would do for us,
            // read the JavaDoc for the class bellow to know exactly what it does, the method names are quite accurate though
           this.testContextManager = new TestContextManager(getClass());
           this.testContextManager.prepareTestInstance(this);
         }
         ...
     }
    
  • 有一个github项目,它建立在以前的博客上,但以一种通用的方式增加了支持

    @SuppressWarnings("InstanceMethodNamingConvention")
    @ContextConfiguration(classes = {ServiceTest.class})
    public class SpringAwareTest {
    
        @ClassRule
        public static final SpringAware SPRING_AWARE = SpringAware.forClass(SpringAwareTest.class);
    
        @Rule
        public TestRule springAwareMethod = SPRING_AWARE.forInstance(this);
    
        @Rule
        public TestName testName = new TestName();
    
        ...
    }
    

  • 因此,您可以使用一个实现其中一种方法的基本类,以及从中继承的所有测试。

    您可以使用Spring附带的SpringClassRule和SpringMethodRule

    import org.junit.ClassRule;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.springframework.test.context.junit4.rules.SpringClassRule;
    import org.springframework.test.context.junit4.rules.SpringMethodRule;
    
    @RunWith(Parameterized.class)
    @ContextConfiguration(...)
    public class MyTest {
    
        @ClassRule
        public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
    
        @Rule
        public final SpringMethodRule springMethodRule = new SpringMethodRule();
    
        ...
    

    JUnit4.12还有另一个解决方案,不需要Spring4.2+

    JUnit 4.12引入了允许将参数化测试和Spring注入相结合的功能

    public class SpringParametersRunnerFactory implements ParametersRunnerFactory {
    @Override
      public Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {
        final BlockJUnit4ClassRunnerWithParameters runnerWithParameters = new BlockJUnit4ClassRunnerWithParameters(test);
        return new SpringJUnit4ClassRunner(test.getTestClass().getJavaClass()) {
          @Override
          protected Object createTest() throws Exception {
            final Object testInstance = runnerWithParameters.createTest();
            getTestContextManager().prepareTestInstance(testInstance);
            return testInstance;
          }
        };
      }
    }
    
    工厂可以添加到测试类中,以提供完整的弹簧支持,如和

    如果您需要静态方法中的Spring上下文来提供测试实例的参数,请在这里查看我的答案。

    自己处理应用程序上下文 对我有效的是有一个
    @RunWith(Parameterized.class)
    测试类,“手动”管理应用程序上下文

    为此,我使用
    @ContextConfiguration
    中的相同字符串集合创建了一个应用程序上下文。因此,与其

    @ContextConfiguration(locations = { "classpath:spring-config-file1.xml",
        "classpath:spring-config-file2.xml" })
    
    我有

    对于我需要的每个@Autowired,我都是从创建的上下文中手工获取的:

    SomeClass someBean = ctx.getBean("someClassAutowiredBean", SomeClass.class);
    
    不要忘记在结尾处关闭上下文:

    ((ClassPathXmlApplicationContext) ctx).close();
    

    这是另一个最新的解决方案,非常好,使用第一种方法,您只需在组件上使用
    @Autowired
    ,即可正确注入。另外,我可以使用
    @SpringApplicationConfiguration
    而不是
    @ContextConfiguration
    ,它工作得很好,不确定区别是什么…您的第一个链接似乎已失效:-(@mavarazy我尝试了第一个解决方案:工作!非常感谢。@keyoxy是否可以并行运行所有测试?
    SomeClass someBean = ctx.getBean("someClassAutowiredBean", SomeClass.class);
    
    ((ClassPathXmlApplicationContext) ctx).close();