Saturday, 21 January 2012

Unit tests with embeded tomcat artifacts

In the 7.x releases of Apache Tomcat, some maven artifacts are now published which include a nice and fluent embeded api to run a Tomcat instance.

So it's a nice opportunity to use it writing units to test servlets, rest api etc..
But until 7.0.25 it was only possible to do it with using a barcoding port which can cause some issues on ci servers where you are not sure ports are not used by something else running.

I have personally sended a RFC to ITEF to have port allocation for only my personal use on my birthday year or zip code port but strangely this RFC was never approved :-).

Now you can use the java ServerSocket port 0 feature to use any free port available on the machine.
It has been fixed with the issue 52028.

So now you can write a unit test as it (here a test with a REST service provided by Apache CXF).

public void startTomcat()
throws Exception
tomcat = new Tomcat();
tomcat.setBaseDir( System.getProperty( "" ) );
tomcat.setPort( 0 );

Context context = tomcat.addContext( "", System.getProperty( "" ) );

A context param in your web.xml:


In the code

ApplicationParameter applicationParameter = new ApplicationParameter();
applicationParameter.setName( "contextConfigLocation" );
applicationParameter.setValue( "classpath*:META-INF/spring-context.xml" );
context.addApplicationParameter( applicationParameter );

A listener class in your web.xml:


In the code

context.addApplicationListener( ContextLoaderListener.class.getName() );

CXF servlet declaration in your web.xml:



In the code:

tomcat.addServlet( context, "cxf", new CXFServlet() );
context.addServletMapping( "/restServices/*", "cxf" );


port = tomcat.getConnector().getLocalPort();

System.out.println("Tomcat started on port:"+port);

So now you can test/consume you REST services on localhost with the port.

Don't miss to shutdown the tomcat instance on tearDown or @After

public void stopTomcat()
throws Exception

If you use Maven you need the following dependencies:


As samples talks more than long docs ("Code talks, bullshit walks" :-) ).
The tomcat maven archetype has been improved with a sample. (see previous post)

Have Fun!

Friday, 13 January 2012

Tomcat Maven plugin archetype. Sample talks more than long documentation :-)

As code sample talks more than long and borying documentation (or maybe because I don't like to write too long documentation :-) ), I have writen an archetype for the Apache Tomcat Maven Plugin.

Some features describe in this post are now implemented.

As it's not yet released but soon !, just use :

mvn archetype:generate \
-DarchetypeGroupId=org.apache.tomcat.maven \
-DarchetypeArtifactId=tomcat-maven-archetype \
-DarchetypeVersion=2.0-SNAPSHOT \
[INFO] Using property: groupId = org.apache.tomcat.maven
Define value for property 'artifactId': : tomcat-sample (project will be created in ./tomcat-sample )
cd tomcat-sample

You can run your webapp with: mvn tomcat6:run or mvn tomcat7:run (depends on tomcat version you want)
And hit your browser to http://localhost:9090 and you will use a very complicated hello world webapp sample :-)

Now you can try: mvn clean install .
You will see a selenium test running (by default firefox), use -Pchrome for using chrome should work too with -Piexplore (not tested :-) ).

Note you have now an executable war.
Try it !

cd basic-webapp-exec/target/
java -jar basic-webapp-exec-1.0-SNAPSHOT-war-exec.jar -httpPort 9191

And hit your browser to http://localhost:9191.
So you have a tomcat7 running our fabulous application and without installing nothing !

More details on the project

This archetype build a simple project with some maven modules. IMHO it's nice layout to use.

basic-api (service interface)
basic-api-impl (service default impl)
basic-webapp (our webapp module)
basic-webapp-exec (module to generated executable war)
basic-webapp-it (module to run selenium tests with generated war)

The application is exposing a REST service called HelloService (in basic-api module)

@Path( "HelloService" )
public interface HelloService
@Path( "sayHello/{who}" )
@Produces( { MediaType.TEXT_PLAIN } )
String sayHello( @PathParam( "who" ) String who );

The implementation is in the module basic-api-impl.
Note we use Apache Cxf to provide REST services (for more details have a look at the various spring files).

The webapp is a simple page based on jquery and twitter bootstrap.

So have fun !