Category: Selenium, Spring Framework, Testing Gene De Lisa @ 6:43 am —
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...

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.

1 person has left a comment

#1

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.

Kevin Gann wrote on July 18, 2008 - 6:04 pm
You can leave a response, or trackback from your own site.

Write Your Comment

Comment Guidelines: Basic XHTML is allowed (a href, strong, em, code). All line breaks and paragraphs will be generated automatically.

You should have a name, right? 
Your email address, I promised I won't tell it to anyone. 
If you have a web site or blog, you can type the URL right here. 
This is where you type your comments. 
Remember my information for the next time I visit.