Maven Folder Layout: Should I host tests in EAR or its submodules?
We have an EAR project with multiple submodules (multiple EJBs, web projects, application clients, etc.). The natural scope for unitary tests is their respective submodules (since they must test isolated blocks).
In a short period of time, we have implemented non-obvious test dependencies. Projects were mocking features from other projects, etc. Soon our architecture evolved into several standalone jar files with mocks (web project 1 mocks, ejb 2 mocks, etc.); we do this mockery of the EAR and consume the layouts in submodules ("Skinny War" style).
EAR
Modules
WEB 1
WEB 2
EJB 2
EJB 3
etc
Libs
Shared library 1
Shared Library 2
Testing dependencies
WEB 1 mocks
WEB 2 mocks
EJB 1 mocks
EJB 2 mocks
etc
WEB1
Uses EJB 1 and EJB 3
Uses Shared Library 1
Testing
Consumes EJB 1 and EJB 2 mocks
Either way, the consensus among our team is that bullying is getting out of hand. We want to evolve towards Arkillian and test inside the container (for example, regarding integration tests). We also present ATTD (originally just functional tests with Drone, but I want you to have a fully functional Thucydidies + JBehave or EasyB program soon).
Tests can depend on the resources of multiple submodules. ShrinkWrap is there to ensure things don't get out of hand.
So my question is: Where should I put tests, stories, Arquillian config files, etc.?
It seems to me that EAR is the best place to group everything:
EAR
Modules
Test
src
Java
Test 1
Test 2
Resources
Configuration Files
Stories
Story 1
Story 2
This will allow us to have a single single report, forget about inter-module dependencies, have one configuration point, etc.
But I could be wrong (it has advantages in dealing with the granularity of each module).
So what is considered the best practice for Arquillian tests: Should I put my test files in an EAR project? Should I include integration / acceptance tests in an EAR project and unitary tests in submodules? Or should I put everything in submodules?
Update: An alternative approach. Should I isolate the integration tests into a separate module? If so, how (how do I install dependencies, configure Arquillian, etc.)?
source to share
Let me give you some practical information on how to organize integration tests with Maven so that other people struggling with it can do the right thing.
I ended up getting recommendations from the fantastic (even if somewhat old) Better Builds with Maven , as well as Codehaus Maven and an integration testing guide .
-
Use the top level project of the aggregator:
myproject myproject-ear myproject-war myproject-ejb ... myproject-integration-tests
-
As suggested by mchamati , each module tests itself with unit tests (as before). Unit tests are fast and can run on every build.
- Also for unit tests, it turns out that my initial strategy was not that bad. I still have several modules tied to the EAR as managed dependencies.
-
Have a separate module for integration tests, its packaging type can be pom; (you won't be creating a real deployable artifact from this project, and also, as the number of tests starts to grow, it might make sense to turn it into another different pom aggregator):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <artifactId>myproject</artifactId> <groupId>com.mycompany</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.myproject</groupId> <artifactId>myproject-integration-tests</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging>
-
The following Maven integration tests should go to
src/it
:<build> <testSourceDirectory>src/it</testSourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> <executions> <execution> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin>
-
Use failsafe to run integration tests:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.17</version> <configuration> <encoding>${project.build.sourceEncoding}</encoding> </configuration> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.17</version> </dependency> </dependencies> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin>
-
Have your integration-project import the ear project dependencies (and whatever else you need). I'm not sure if this is considered good practice as it hasn't been mentioned in any guides, but it works very well for me.
<dependency> <groupId>com.mycompany</groupId> <artifactId>my-project-ear</artifactId> <version>1.0-SNAPSHOT</version> <type>pom</type> </dependency>
-
Centralize arquillian relevant configuration in the integration tests module:
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <version>${arquillian.version}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <version>${arquillian.version}</version> <scope>test</scope> </dependency> <!-- Arquillian container related dependencies, etc -->
-
Follow the failover naming convention for test files.
src/it/java com/mycompany/myproject mypackage MyIT.java MySecondIT.java anotherpackage YetAnotherIT.java
-
Profit
In the top-level aggregator project:
-
mvn test
⇒ Runs quick unit tests full of mocks -
mvn verify
⇒ Performs real integration / functional / acceptance tests (may be slow)
-
Additional hints: If you are using a CI server like Jenkins , set up your nightly builds to run integration tests (i.e. get a build call mvn verify
). Do not deploy unverified builds to homologation or production servers.
source to share
I once had the same problem as yours, it has more to do with an architectural issue, CBD (Component Based Development). Since you have submodules, which I prefer to call components, they should test themselves (unit tests), and the dependency between them should not be circular. Shared configurations, to avoid duplication, can be a split component called a vertical component (split across many components, more classified as a "util" component than a "business component"). Usually the report components do not depend on them but the EAR which is the "final node" so the report components depend on many components.
I'm not sure if I answered your needs, but in my opinion this is the root cause of your problem, which once ran into me and decided to redesign the component dependency tree.
I can't help much with Arquillian, but the CBD concept is that the component (submodule) is self-contained, they have to do whatever they need to do, even test and mock the data. You should find ways to solve this architectural problem, for example Maven Dashboard might help you to unify and analyze your test results, look at maven-dashboard or even sonar .
It's useless to draw the tree here as it doesn't display the dependency tree, previous m2-eclipse plugin used to draw it, but they removed the functionality how bad it is. However, forget about technology when planning your CBD. EAR does not have modules, unless strictly necessary for its needs, it can be a technology barrier. Typically, EAR depends on WAR, and WAR depends on JAR, which depends on other JARs - each of them is a component.
Based on the first example you provided, Shared lib is a vertical component, it doesn't depend on your module, I'm not sure about the technologies / frames you have chosen, but with Spring we can easily share config files between components (vertical component like component "base test", which can, for example, provide classes to facilitate implementation of configuration and tests). Moving on to an example, subodule2 might depend on subodule1 , in which case subodule1 will have its own tests and mocks; subodule2 will have its own tests and mocks, and when using subodule1 it will be given fake data.
You may already know, but I recommend two books: (1) the classic "Domain Driven Project: Complexity at the Heart of Software" by Eric Evans; (2) "UML Components: A Simple Process for Specifying Component-Based Software" by John Cheesman and John Daniels (author).
source to share