Archive for April, 2010

Integration test

Integration test

Integration test will be supported in next release (0.8 targeted for beginning of may).

Since the beginning of the project, easyant was already designed to have a dedicated phase to run integration test.
Until now, no plugin was contributing to this phase. This will change in next release, were the following plugins will be provide ready to use targets to run integration-test :
* junit plugin
* testng plugin
* antunit plugin

 

What are the differences between UnitTest and IntegrationTest ?

Usually people think that if they use Junit they do Unit Tests, but in reality the difference if more subtile. Let’s see in details the main differences.

UnitTests

In theory, UnitTest are supposed to test the method content but not a whole choreography. It should be a stand-alone test which is not related to other resources.
Example: If you’re writing unit test on your service layer, you’re service is probably calling classes from the data access layer. So the UnitTest should test only the service method and not the sub calls done by data access layer.

UnitTests are supposed to check internal workings of a class by testing portions of code (“units”). It specify and test one point of the contract of single method of a class. This should have a very narrow and well defined scope. Complex dependencies and interactions to the outside world are stubbed or mocked.
In the previous example we should “mock” the call to the data access layer.

The objective is simple, we want to be sure that :

  • the method (excluding all sub calls) do what it is supposed to do
  • evaluate the code coverage
  • have a robust code
  • unit test will run fast (a few seconds)

Usually tests are done by developers to enforce their code base.

IntegrationTest

In opposite, IntegrationTests are designed to check inter-operation of multiple subsystems (multiple units).
There is whole spectrum there, from testing integration between two classes, to testing integration with the production environment.
Integration test can :

  • validate that all pieces of code developed individually works together.
  • test the whole choreography of a given use case (business choreography, everything from the UI to the DB, inter-operation between applications, etc…)
  • validate the application as a functional point of view (usually called Acceptance Test) before a release
  • run UI tests (done by tools like selenium, sahi, etc…)

Comparing to UnitTests, IntegrationTest can be longer. Usually we should run integration-test on nightly builds or at least before each release.

How to manage this with easyant ?

EasyAnt will provide ready to use targets configured over conventions to handle separately UnitTests and IntegrationTests.
Here again even if we provides conventions, we never lock you in, so you can adapt this to your needs.

By convention :

  • UnitTest are stored in the src/test directory
  • IntegrationTest are stored in the src/integration test directory.

UnitTest

The directory structure of Unit Tests looks like this :

  • src/test/java : for test source code (note that this can be configured through the property src.test.java)
  • src/test/resources : for test resource files (note that this can be configured through the property src.test.resources)

Note: this also apply with non-java project (like groovy / scala project).
Groovy project :

  • src/test/groovy for test source code (note that this can be configured through the property src.test.groovy)

Scala project :

  • src/test/scala for test source code (note that this can be configured through the property src.test.scala)

Antunit :

  • src/test/antunit for antunit test (note that this can be configured through the property src.test.antunit)

IntegrationTest

The directory structure for integration test looks like this:

  • src/integration-test/java for integration test source code (note that this can be configured through the property src.test.integration.java)
  • src/integration-test/resources for integrationtest resource files (note that this can be configured through the property src.test.integration resources)

Note: this also apply with non-java project (like groovy / scala project).
Groovy project :

  • src/integration-test/groovy for integration test source code (note that this can be configured through the property src.test.integration.groovy)

Scala project :

  • src/integration-test/scala for integration test source code (note that this can be configured through the property src.test.integration.scala)

Antunit :

  • src/integration-test/antunit for antunit integration test (note that this can be configured through the property src.test.integration antunit)

Others :
You can also write your own plugin by following this guide.
Your plugin should provide a target bound to integration-test. This plugin will run test-scenario’s stored in your phase to run scenario stored in src/integration-test

Example: if you want to write your own selenium plugin you could run the scenario stored in src/integration-test/selenium

findclasspath we loves you !

In the next release we’re planning to introduce a new task named <findclasspath> that will help a lot plugin writers to locate some external ressources (like a SDK).

This task is designed to locate the right version of a SDK (for groovy / scala, but maybe for others SDK like android etc…).

Let’s see in details how we can use it

The <findclasspath> task is designed to locate the right version of a SDK (for groovy / scala, but maybe for others SDK like android etc…) based on the pattern chain of responsability.

Really basic sample :

1 <ea:findclasspath org="org.codehaus.groovy" module="groovy-all" revision="1.0"/> 

 

By default if you do not specify anything inside the findclasspath task, easyant will use the default strategies :

  • ProjectDependenciesStrategy : will check if the specified dependency is contained as a project dependencies. If there is no exact match it will give a try based on organisation name. If found easyant will use the specified version in the project dependencies.
  • BasicConfiguration : will use the specified dependency (declared in <findclasspath>)

Using additional strategy

You can define (or override) the default behavior and plug your own strategy.
By default, EasyAnt came with an additional strategy : environment strategy.

This strategy can be referenced as a nested element of <findclasspath>.
If you choose to use additionnal strategy you need to define the whole chain (ordered). This allow you to interfer with the two default strategies

Say for example you want to :

  • check project dependencies
  • if not found check environment variables
  • if not found use the specified version in findclasspath argument

The task will looks like this :

1 <ea:findclasspath org="org.codehaus.groovy" module="groovy-all" revision="1.0"> 2 <project-dependency-strategy/> 3 <environment-strategy env="GROOVY_HOME"/> 4 <basic-configuration-strategy/> 5 </ea:findclasspath> 

 

Writting your own

To write your own strategy you just need to write a java class extending org.apache.easyant.tasks.findclasspath.AbstractFindClassPathStrategy.

This class will force you to implement abstract methods

1 public class MyOwnStrategy extends AbstractFindClassPathStrategy{ 2 protected boolean doCheck() { 3 //do your job 4 //the doCheck method should return true if the strategy was able to build the classpath 5 } 6 } 7 

 

As every ant tasks this class should be configured through a taskdef and be in the plugin’s classpath.

Then you need to define the whole chain (ordered). This allow you to interfer with the two default strategies and to plug your own in the right place.

So you could do the following in your plugin :

1 <ea:findclasspath org="org.codehaus.groovy" module="groovy-all" revision="1.0"> 2 <project-dependency-strategy/> 3 <mystrategy/> 4 <basic-configuration-strategy/> 5 </ea:findclasspath> 

 

As a functionnal point of view it will:

  1. check if the specified sdk (org.codehaus.groovy#groovy-all) is in project dependencies
  2. if not found it will use your own strategy
  3. if still not found it will run the basic strategy and download the sdk specified as paramters (org.codehaus.groovy#groovy-all;1.0)

By discussing with friends, i was thinking of having an optional FileSystemStategy.
The idea would be to handle OS specific installations like :

 1 <ea:findclasspath org="org.codehaus.groovy" module="groovy-all" revision="1.0">  2 <projectDependenciesStrategy/>  3 <environnementStrategy env="GROOVY_HOME"/>  4 <!-- if your os is windows find the groovy-all jar in c:\Program Files\groovy -->  5 <filesystemStategy os="windows" path="c:\Program Files\Groovy"/>  6 <!-- if your os is linux find the groovy-all jar in c:\Program Files\groovy -->  7 <filesystemStategy os="linux" path="/usr/lib/groovy/"/>  8 <filesystemStategy os="mac" path="/usr/lib/groovy/"/>  9 <pluginConfigurationStrategy/> 10 </ea:findclasspath> 

 

OS attribute could use kind of regexp and maybe handle more precisly the target os (Windows ? Windows XP? Windows Vista ? Linux ? Ubuntu ?)
Is there any way to handle as a lower level the target os (debian ? ubuntu ? mac OS 10 ? )

What do yo think about this optionnal strategy ?
Should we provide it as an option and let plugins writer configure it to their needs?