Is there a way to get a class that extends AbstractTransa开发者_Go百科ctionalJUnit4SpringContexts to play nicely with JUnit's own @RunWith(Parameterized.class), so that fields marked as Autowired get wired in properly?
@RunWith(Parameterized.class)
public class Foo extends AbstractTransactionalJUnit4SpringContextTests {
@Autowired private Bar bar
@Parameters public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
@Test public void someTest(){
bar.baz() //NullPointerException
}
}
See http://jira.springframework.org/browse/SPR-5292 There is a solution.
You can use a TestContextManager from Spring. In this example, I'm using Theories instead of Parameterized.
@RunWith(Theories.class)
@ContextConfiguration(locations = "classpath:/spring-context.xml")
public class SeleniumCase {
@DataPoints
public static WebDriver[] drivers() {
return new WebDriver[] { firefoxDriver, internetExplorerDriver };
}
private TestContextManager testContextManager;
@Autowired
SomethingDao dao;
private static FirefoxDriver firefoxDriver = new FirefoxDriver();
private static InternetExplorerDriver internetExplorerDriver = new InternetExplorerDriver();
@AfterClass
public static void tearDown() {
firefoxDriver.close();
internetExplorerDriver.close();
}
@Before
public void setUpStringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
@Theory
public void testWork(WebDriver driver) {
assertNotNull(driver);
assertNotNull(dao);
}
}
I found this solution here : How to do Parameterized/Theories tests with Spring
You can use SpringClassRule and SpringMethodRule for this purpose
@RunWith(Parameterized.class)
@ContextConfiguration(...)
public class FooTest {
@ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Autowired
private Bar bar
@Parameters
public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
@Test
public void someTest() {
bar.baz() //NullPointerException
}
}
No, you can't. The superclass has:
@RunWith(SpringJUnit4ClassRunner.class)
which assures that the tests are run within spring context. If you replace it, you are losing this.
What comes to my mind as an alternative is to extend SpringJunit4ClassRunner
, provide your custom functionality there and use it with @RunWith(..)
. Thus you will have the spring context + your additional functionality. It will call super.createTest(..)
and then perform additional stuff on the test.
I've had to handle the transactions programmatically (see http://www.javathinking.com/2011/09/junit-parameterized-test-with-spring-autowiring-and-transactions/):
@RunWith(Parameterized.class)
@ContextConfiguration(locations = "classpath*:/testContext.xml")
public class MyTest {
@Autowired
PlatformTransactionManager transactionManager;
private TestContextManager testContextManager;
public MyTest (... parameters for test) {
// store parameters in instance variables
}
@Before
public void setUpSpringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
@Parameterized.Parameters
public static Collection<Object[]> generateData() throws Exception {
ArrayList list = new ArrayList();
// add data for each test here
return list;
}
@Test
public void validDataShouldLoadFully() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
status.setRollbackOnly();
try {
... do cool stuff here
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
});
}
Here's how I made it work in Spring Boot 1.5.7
:
Add the
@RunWith(Parameterized.class)
annotation to your classInject your dependency as class field with:
@Autowired private Bar bar;
Add your parameter/s as class fields:
private final int qux; private final Boolean corge; private final String grault;
Add a constructor to initialize the parameter/s as follows:
public Foo(int qux, Boolean corge, String grault) throws Exception { this.qux = qux; this.corge = corge; this.grault = grault; new TestContextManager(getClass()).prepareTestInstance(this); }
Add a static method
data
that returns a Collection containing the values of your parameters at each iteration, respecting the order by which they are passed to the constructor:@Parameterized.Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{ { 1, Boolean.FALSE, "Hello" }, { 2, Boolean.TRUE, null }, { 3, null, "world" } }); }
Write your test using the class fields declared above like follows:
@Test public void someTest(){ // Some arrangements // Some actions assertThat(myTestedIntValue, is(equalTo(qux)); assertThat(myTestedBooleanValue, is(equalTo(corge)); assertThat(myTestedStringValue, is(equalTo(grault)); }
Inspired by Simon's solution, you can use TestContextManager also with Parameterized runner:
@RunWith(Parameterized.class)
@ContextConfiguration(locations = "classpath:/spring-context.xml")
public class MyTestClass {
@Parameters public static Collection data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
@Before
public void setUp() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
}
}
Here is full example
I am not sure about handling @Transactional in this case.
精彩评论