07 October 2008

If you've ever used the testing support in prior versions of Spring you know that it was essentially JUnit 3.x, oriented. There were ways to make those scaffolding classes work for (my personal favorite) TestNG or even Junit 4, but they largely were engineering hacks, not real solutions. For example, with the TestNG case you could override the setUp method and annotate it such that TestNG would call that method for setup, while also complying with Junit's interface requirements. Now there's a better way. Here's how I got it workiung with Maven and Surefire and TestNG 5.7. First, I added support for TestNG 5.7 (which is current as of this writing.):

<dependency> <artifactId>testng</artifactId> <groupId>org.testng</groupId> <version>5.7</version> <classifier>jdk15</classifier> </dependency>

Then I added support for SureFire to the Maven POM:

  <plugins> 
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> >
<version>2.4</version>
<configuration>
<suiteXmlFiles>

<suiteXmlFile>${basedir}/src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>

</plugin>

</plugins>

Finally, it comes time to write the test. Maven has a structure that's realized using the following command:

mkdir -p src/{test,main}/{java,resources};

Your unit test code goes into src/test/java and your testng.xml goes into src/test/resources.

Here's an example of the testng.xml:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"
> <suite name="myProject" verbose="5">
<test name="serviceTests">
<packages>
<package
name="com.joshlong.myProject.test.services"/>
</packages>
</test>

</suite>

And, finally, here's an example of a test class that works:

package com.joshlong.myProject.tests.services;
import com.joshlong.myProject.utils.LoggingUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
// THIS ONE's IMPORTANT! There are one of these for each of the 3 frameworks you're likely to want to use.
import static org.testng.Assert.assertTrue;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
* @author Josh Long
*/
@ContextConfiguration(locations = {"classpath:service-context.xml", "classpath:test-context.xml"})
public class MyProjectTest extends AbstractTransactionalTestNGSpringContextTests {

@BeforeMethod public void announceClass() throws Throwable {
loggingUtils.log("Inside of MyProjectTest!");
}


@Autowired
private LoggingUtils loggingUtils; // this gets automatically injected from one of the contexts listed in the @ContextConfiguration annotations.

@Test
public void testBasicMath() throws Throwable {
loggingUtils.log("foo()");
assertTrue( 1 < 2, "1 < 2 -- pray that this is correct and that this test never does fail!");
}
}