Maven folder layout: Should I place tests in the E

2019-06-09 01:04发布

We have an EAR project with several sub-modules (multiple EJBs, Web Projects, Application Clients, etc). The natural scope for unitary tests are their respective sub-modules (since they are supposed to be testing isolated units).

In a short amount of time we have introduced non obvious testing dependencies. Projects were mocking functionality from other projects, etc. Soon our architecture evolved to several stand-alone jar files with mocks (web project 1 mocks, ejb 2 mocks, etc); we wire those mocks against the EAR and consume the mocks in the sub-modules ("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

Anyway, the consensus among our team is that mocks are getting out of control. We want to evolve towards Arquillian and testing inside the container (e.g., towards Integration tests). We are also introducing ATTD (initially just functional tests with Drone, but I wish to have a fully functional Thucydidies + JBehave or EasyB setup soon).

Tests may depend on resources from multiple sub-modules. ShrinkWrap is there to guarantee that things do not get out of hand.

So my question is: Where should I put tests, stories, Arquillian configuration files and so on?

I feel like the 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 would allow us to have a single unified report, forget about inter-modular dependencies, have a single point of configuration and so on.

But I might be wrong (working with per-module granularity have its advantages).

So what is considered best practice for Arquillian tests: Should I place my test files in the EAR Project? Should I place integration / acceptance tests in the EAR project and unitary tests in the sub-modules? Or should I put everything in the sub-modules?


Update: Alternative approach. Should I isolate integration tests into a separate module? If so, how (how should I set dependencies, configure Arquillian, etc)?

2条回答
Ridiculous、
2楼-- · 2019-06-09 01:14

Let me put a little bit of practical information about how to organize integration tests with Maven so that other people struggling with it may Do The Right Thing™ .

I ended up following advice from the fantastic (even if somewhat old) Better Builds with Maven as well as Codehaus Maven and Integration Testing Guide.

  1. Use an aggregator top level project:

    myproject
        myproject-ear
        myproject-war
        myproject-ejb
        ...
        myproject-integration-tests
    
  2. As suggested by mchamati, have every module test itself with unit tests (just as before). Unit tests are fast and can be run on every build.

  3. Also for unit tests, it turns out that my initial strategy was not so bad. I still have several mock modules bound to the EAR as managed dependencies.
  4. Have a separate integration tests module, its packaging type can be pom; (you will not build an real deployable artifact out of this project; also, when the number of tests begin to grow, it may make sense to turn it into yet another another aggregator pom):

    <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>
    
  5. Following Maven conventions integration tests should go into 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> 
    
  6. 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>
    
  7. Have your integration-tests project import the ear project dependencies (and everything else that you need). I'm not sure if this is considered good practice since it was not mentioned in any of the guides, but It worked very well for me.

    <dependency>
        <groupId>com.mycompany</groupId>
        <artifactId>my-project-ear</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>pom</type>
    </dependency>
    
  8. Centralize arquillian related 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 -->
    
  9. Follow failsafe naming conventions for test files.

    src/it/java
        com/mycompany/myproject
            mypackage
                MyIT.java 
                MySecondIT.java
            anotherpackage
                YetAnotherIT.java  
    
  10. Profit

    Under the top level aggregator project:

    1. mvn test ⇒ Runs the fast unit tests full of mocks
    2. mvn verify ⇒ Runs the real integration / functional / acceptance tests (may be slow)

Extra hint: If you are running an CI Server such as Jenkins setup your nightly builds to run the integration tests (i.e., have your build call mvn verify). Do not deploy unverified builds to homologation or production servers.

查看更多
Lonely孤独者°
3楼-- · 2019-06-09 01:25

I once had the same issue you are having, this is more to an architectural issue, CBD (Component Based Development). As you have sub-modules, 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, could be a separated component called vertical component (shared across many components, more classified as a "util component" than a "business component"). Report components, commonly, have no dependency to them but the EAR, which is a "final node", so report components will depend from many components.

I am not sure I answered your needs, but in my opinion this is the root cause of your problem, faced once by me and solved redesigning the components dependency tree.

I cannot help a lot with Arquillian, but concept of CBD is that a component (sub-module) is self-sufficient, they must do everything they need to do, even tests and mock data. You must find ways to solve this architectural issue, for example, Maven Dashboard probably can help you unify and analyze your test results have a look at maven-dashboard or even sonar.

It is useless to draw a tree here as it will not show the dependency tree, previous m2-eclipse plugin used to draw it but they removed the functionality, how bad. However, forget about technologies when desiging CBD. EAR does not have modules if not strictly necessary to its needs, this could be a technology barrier. Generally, EAR depends on the WARs and WARs depends on JARs that depends on other JARs - each one of them is a component.

Based in the first example you gave, a Shared lib is a vertical component, it does not depend on any module of yours, I am not sure about the technologies/frameworks chosen in your situation, but with Spring we can easily share configuration files between components (vertical component like a "base-test" component that could, for example, provide classes to ease the configuration and tests implementation). Moving on with the example, submodule2 could depend on submodule1, in that case submodule1 will have its own tests and mocks; submodule2 will have its own tests and mocks and, when using submodule1, mocked data will be provided to it.

Maybe you already know, but I recommend two books: (1) the classic "Domain-Driven Design: Tackling Complexity in 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).

查看更多
登录 后发表回答