如何使用参数化运行 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 测试?