Thursday, December 16, 2010

Curried closures and static methods

If the same static utility method is called from multiple places in Groovy code, and some of the parameters to the method are always the same, curried closure is a nice way to shorten the syntax. For instance, the following static method retrieves all the entries from a list that match a certain pattern:


class MatchHelper {
    static List getMatches(pattern, list) {
        list.grep(pattern)
    }
}

Method getMatches is then called from several places in the code:

def pattern = ~/^[Tt].*/
...
List cars = ["Murano", "Touareg", "Taurus"]
List matchedCars = MatchHelper.getMatches(pattern, cars)
assert  ["Touareg", "Taurus"] == matchedCars
...
List veggies = ["Tomato", "Broccoli", "Sprout"]
List matchedVeggies = MatchHelper.getMatches(pattern, veggies)
assert ["Tomato"] == matchedVeggies
...
List cities = ["Torino", "Sydney", "Tegucigalpa"]
List matchedCities = MatchHelper.getMatches(pattern, cities)
assert ["Torino", "Tegucigalpa"] == matchedCities

Not only does each code snippet calls MatchHelper.getMatches(), but also ~/^[Tt].*/ is passed as the first parameter each time. Instead the code can be shorted this way:

def getTMatches = MatchHelper.&getMatches.curry(~/^[Tt].*/)
...
List cars = ["Murano", "Touareg", "Taurus"]
List matchedCars = getTMatches(cars)
assert  ["Touareg", "Taurus"] == matchedCars
...
List veggies = ["Tomato", "Broccoli", "Sprout"]
List matchedVeggies = getTMatches(veggies)
assert ["Tomato"] == matchedVeggies
...
List cities = ["Torino", "Sydney", "Tegucigalpa"]
List matchedCities = getTMatches(cities)
assert ["Torino", "Tegucigalpa"] == matchedCities

A little less code and a little more elegance. Typical Groovy.

Friday, December 3, 2010

Properly defining integration tests in Maven POM

By default, Maven executes all tests during test phase, no matter if the class name ends with 'Test' or 'IntegrationTest'. So, unless integration tests are placed in a separate module (which is not a bad idea at all), some POM crafting is required to make sure that unit tests execute during test phase and integration tests execute during integration-test phase. There are 2 ways to do that:

1. Maven surefire plugin

Maven uses this plugin by default for all test runs. So no special configuration is needed to run unit tests. This is what needs to be added for integration tests:


<build>
    <plugins>
         ...
        <plugin>
             <groupId>org.apache.maven.plugin</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>

                  <!-- at first, all integration tests need to be explicitly excluded 
                         from all test executions, be it test phase 
                         or any other phase where maven-surefire-plugin is invoked 
                         on a custom basis.
                     -->
                  <excludes>
                      <exclude>**/*IntegrationTest.java</exclude>
                  </excludes>

              </configuration>
              <executions>
                  <execution>
                      <id>integration-test</id>
                      <goals>
                          <goal>test</goal>
                      </goals>
                      <phase>integration-test</phase>
                      <configuration>

                          <!-- Here integration tests are included 
                                 at the integration-test phase separately.
                              -->
                          <includes>
                              <include>**/*IntegrationTest.java</include>
                          </includes>
                          <!-- a parameter called 'skipIntegration' is
                                 the same as 'skipTests' except only
                                 for integration tests -->
                          <skipTests>${skipIntegration}</skipTests>
                      </configuration>
                  </execution>
              </executions>
           </plugin>
           ...
      </plugins>
</build>

2. Maven failsafe plugin

This maven plugin includes integration test classes whose names fit '*IT' or '*ITCase' patterns and executes them during integration-test phase. If classes are named that way, then it's enough to simply throw in default maven-failsafe-plugin configuration. However, if classes are named using '*IntegrationTest' pattern, then they have to be excluded from test phase in maven-surefire-plugin configuration, and that pattern has to be defined in maven-failsafe-plugin configuration:

<build>
    <plugins>
         ...
        <plugin>
             <groupId>org.apache.maven.plugin</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>
                  <excludes>
                      <exclude>**/*IntegrationTest.java</exclude>
                  </excludes>
             </configuration>
         </plugin>

         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-failsafe-plugin</artifactId>
             <configuration>
                 <includes>
                     <include>**/*IntegrationTest.java</include>
                  </includes>

                  <skipTests>${skipIntegration}</skipTests>  
              </configuration>
              <executions>
                  <execution>
                      <id>integration-test</id>
                      <phase>integration-test</phase>
                      <goals>
                          <goal>integration-test</goal>
                      </goals>
                  </execution>
                  <execution>
                      <id>verify</id>
                      <phase>verify</phase>
                      <goals>
                          <goal>verify</goal>
                      </goals>
                  </execution>
              </executions> 
          </plugin>    
         ...
     </plugins>
</build>