如何使用参数化运行 JUnit SpringJUnit4ClassRunner?

Posted

技术标签:

【中文标题】如何使用参数化运行 JUnit SpringJUnit4ClassRunner?【英文标题】:How to run JUnit SpringJUnit4ClassRunner with Parametrized? 【发布时间】:2015-04-18 02:29:11 【问题描述】:

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

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

但是如何结合使用这两个注解呢?

【问题讨论】:

这是另一个最新的解决方案blog.codeleak.pl/2015/08/… 【参考方案1】:

您可以使用 SpringClassRule 和 SpringMethodRule - Spring 提供

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

    ...

【讨论】:

@keyoxy 是否可以并行运行所有测试?【参考方案2】:

至少有 2 个选项可以做到这一点:

    关注http://www.blog.project13.pl/index.php/coding/1077/runwith-junit4-with-both-springjunit4clas-s-runner-and-parameterized/

    您的测试需要如下所示:

     @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项目https://github.com/mmichaelis/spring-aware-rule,它是在之前的博客的基础上构建的,但是以一种通用的方式增加了支持

    @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();
    
        ...
    
    

因此,您可以有一个实现其中一种方法的基本类,并且所有测试都从它继承。

【讨论】:

很好,通过第一种方式,您只需在组件上使用@Autowired,它就会被正确注入。另外,我可以使用@SpringApplicationConfiguration 而不是@ContextConfiguration,效果很好,不知道有什么区别...... 您的第一个链接似乎已失效 :-( @mavarazy 我尝试了第一个解决方案:有效!非常感谢。【参考方案3】:

还有另一个使用 JUnit 4.12 的解决方案,不需要 Spring 4.2+。

JUnit 4.12 引入了ParametersRunnerFactory,它允许结合参数化测试和 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 支持,例如 test transaction、reinit dirty context 和 servlet test。

@UseParametersRunnerFactory(SpringParametersRunnerFactory.class)
@RunWith(Parameterized.class)
@ContextConfiguration(locations = "/test-context.xml", "/mvc-context.xml")
@WebAppConfiguration
@Transactional
@TransactionConfiguration
public class MyTransactionalTest 

  @Autowired
  private WebApplicationContext context;

  ...

如果您需要 @Parameters 静态方法中的 Spring 上下文来为测试实例提供参数,请在此处查看我的答案 How can I use the Parameterized JUnit test runner with a field that's injected using Spring?。

【讨论】:

【参考方案4】:

自行处理应用上下文

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

为此,我使用@ContextConfiguration 中的相同字符串集合创建了一个应用程序上下文。所以不要有

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

我有

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] 
            "classpath:spring-config-file1.xml", "classpath:spring-config-file2.xml"  );

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

SomeClass someBean = ctx.getBean("someClassAutowiredBean", SomeClass.class);

不要忘记在最后关闭上下文:

((ClassPathXmlApplicationContext) ctx).close();

【讨论】:

以上是关于如何使用参数化运行 JUnit SpringJUnit4ClassRunner?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用 Spring ApplicationContext 中的 bean 参数化 JUnit Jupiter 测试?

第284天学习打卡(知识点回顾 springboot Junit5 参数化测试特性)

JUnit测试POST到参数化的API

spring-boot2.0 单元测试JUnit4

创建参数化测试

Junit参数化构造函数 - 参数数量错误