In a previous post I wrote about using JUnit4 with Selenium.
So how about injecting your JUnit run listener via Spring?
My first attempt modified my runner to be a subclass of SpringJUnit4ClassRunner
Then I created the usual XML spring config file but named it after my test class name. So for
FooTests I created FooTests-context.xml. If you want another name you can pass that into
@ContextConfiguration.
Here is a bit of it:
<bean id="Selenium" class="com.thoughtworks.selenium.DefaultSelenium"> <constructor-arg> <value>localhost</value> </constructor-arg> <constructor-arg> <value>4444</value> </constructor-arg> <constructor-arg> <value>*firefox</value> </constructor-arg> <constructor-arg> <value>http://localhost:9080/myapp/</value> </constructor-arg> </bean>
Here is is what I have for the test cases
@RunWith(SpringRunner.class)
@ContextConfiguration
public class FooTests() {
@Autowired
private Selenium selenium;
@Test
public void whatever() {}
}
and the JUnit 4 listener:
public class SpringRunListener extends RunListener {
@Autowired // wishful thinking
private Selenium selenium;
etc.
So there is the problem. Spring will autowire testcases but not the runners nor the listeners.
What is the Spring way? Forget the JUnit RunListener. You write a Spring TestExecutionListener.
But that’s not autowired either so you have to grab your beans yourself. Luckily you have access to
the Spring context.
public class MyTestExecutionListener extends AbstractTestExecutionListener {
private static final Log logger = LogFactory.getLog(MyTestExecutionListener.class);
Selenium selenium;
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
// not autowired so go grab it
selenium = (Selenium) testContext.getApplicationContext().getBean("Selenium");
}
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
Throwable t = testContext.getTestException();
if (t != null) {
report(t); // go ahead and do the screendump using selenium
}
}
and to make your listener get used you add it to the list of test execution listeners in your test classes.
I put it in the superclass of my test classes.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestExecutionListeners(
{
MyTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class
})
public class FooTests ...
But you say, what about that new @Configurable annotation?
Can’t you use DI on an object that Spring does not instantiate?
Stay tuned.
















Development notes by Gene De Lisa on topics relating to
Java and various open source projects such as
the Spring Framework, Hibernate and others.
1 person has left a comment
I’m interested in hearing more about your Spring/Selenium RC adventures. I’m getting ready to rewrite quite a few Selenium tests into using RC and taking the opportunity to create more manageable and reusable code. I’m a QA person by trade so I’m fuzzy on design pattern best practices, but I know from experience that good code makes life easier for everyone.