Skip to main content
blog title image

6 minute read - CI Java For Testers Maven travis-ci

Using travis-ci.org for checking code on github

Jul 17, 2015

image created with js-sequence-diagram

I run all the tests for Java For Testers prior to releasing the book. Since all code shown in the book is pulled out of the source, it should mean that all the source code you see in the book should run.

I thought it would be useful to have a second execution of the code after it has been released to github. (I have the code with all annotations I need to ‘pull’ chunks out, in a different repo, then release the code with annotations removed, to github)

Travis-CI.org looked like a potential candidate since it seemed pretty simple to setup.

With Travis-CI.org, all I had to do was authenticate with my github credentials, then select the Java For Testers code repo:

The first thing travis told me was that I didn’t have a .travis.yml file, so I read the instructions on the travis-ci.org site, and it couldn’t find my file. Since the .travis.yml file needs to be in the root of the repo.

language: java
mvn test

After moving the .travis.yml file to the root, I tried again. Of course, I had mis-read the instructions so I removed mvn test from the .yml file.

language: java

I found the Travis-CI.org yaml file validator github.com/travis-ci/travis-yml useful at this point. And used it for all future changes.

And then, since my src folder is not at the root of the repo, since I might need to release other assets along with the code to support the book. Well, Travis-CI.org couldn’t find the pom.xml.

I added a build line into the .travis.yml file

language: java
script: mvn test -f ./source/pom.xml

And now everything started building. With a few failing @Test methods.

File Testing on Travis

See the @Test methods in Java For Testers aren’t strictly unit tests, so they do interact with the file system and create files.

And some of the examples have hard coded paths which readers will be able to amend, and which work fine on my local machine, but which failed on Travis-CI.org.

Workaround exclude tests

In theory, I could probably amend the examples in the book, but that might make them a little more complicated and confusing. And since this CI run is a ‘secondary’ check, I decided instead to exclude the File tests from the Travis-CI.org build.

Rather than using JUnit suites to do this, I simply excluded them via maven configuration in the plugins section.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.18.1</version>
    <configuration>
    <excludes>
    <!-- exclude file tests from travis-ci.org execution -->
        <exclude>**/FileTest.java</exclude>
        <exclude>**/FileExercisesTest.java</exclude>
        <exclude>**/PropertiesTest.java</exclude>
        <exclude>**/PropertyExercisesTest.java</exclude>
    </excludes>
    </configuration>
</plugin>

see inclusion-exclusion on the maven site for more details.

Of course, now I needed to create a new pom.xml purely forTravis-CI.org, but that was easy enough so now my .travis.yml file looks as follows:

language: java
script: mvn test -f ./source/travis-ci-pom.xml

Fixing File Tests ## Use File and Paths.get and Path

I initially assumed the failures were down to file permissions on travis-ci, and excluded those tests on that environment because I didn’t have time to fix them.

During the proof reading it became apparent to me that the File chapter didn’t represent how I build up paths in the real world. And perhaps, what I was really seeing was a cross platform issue. I hadn’t really made all the code cross platform, so I started to do that.

The first thing was to make sure that I only had hard coded paths in tests which didn’t write to disk. Those that did write to disk needed to use System property "java.io.tmpdir".

I also needed to make sure that I build up paths in a cross platform way. Since the Java file operations on Windows will happily work when your separator is ‘/’, I naively assumed that this would generate cross-platform test code. And since the tests were running on Mac, I naively assumed that it as a travis-ci problem.

However looking at the output from the tests, it was clear that on Linux, the "java.io.tmpdir" needed additional ‘/’ handling to check for it on the end of the string or not. And using File or Path means we don’t need to do that.

So I converted all the path construction code and File chapter to use a combination of File, Path and Paths.get. And lo, the code passed on Windows, Mac and travis-ci Linux.

A win-win result, and now the code runs cleanly cross platform, and the travis-ci build uses the pom.xml with no exclusions necessary.

So now, I run the code on Windows and Mac locally. Then use travis-ci to run on Linux, using JDK7, JDK8 and Open JDK 7.

Locale Dependencies

I also saw that some of my exercise answer code has some locale dependency. Specifically in the calendar exploration.

I originally wrote an answer to one of my examples as follows:

@Test
public void experimentWithCalendarConstants(){
  Calendar cal = Calendar.getInstance();
  cal.set(2013, Calendar.DECEMBER, 15, 23,39, 54);

  assertThat(cal.get(Calendar.DAY_OF_WEEK), is(1));
  assertThat(cal.get(Calendar.DAY_OF_WEEK), is(Calendar.SUNDAY));
  assertThat(cal.get(Calendar.WEEK_OF_MONTH), is(2));
  assertThat(cal.get(Calendar.WEEK_OF_YEAR), is(50));
  assertThat(cal.get(Calendar.DAY_OF_YEAR), is(349));
}

I specifically avoided instantiating Calendar with locale examples because I thought it would introduce additional complexity into the code, but of course, Travis-CI.org isn’t based in the UK so has a different set of date defaults, which only become apparent when using the WEEK_OF_MONTH and WEEK_OF_YEAR calculations.

So I added additional configuration into the example to control the First Day of Week and Minimal Days In First Week

        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.setMinimalDaysInFirstWeek(6);

If I was going to make the code robust then I’d really set the locale properly. e.g. per this stackoverflow example

I chose to make the code in the book simple, knowing that it was primarily going to guide the creation of code to support testing, and that code normally runs under fairly tight configuration. i.e. it doesn’t go out and have to run on multiple devices and lots of operating systems. And if your test code does, then it is at that point that you usually learn to handle the platform differences that are relevant for you specific execution context.

Since Travis-CI.org has the facility to easily build against multiple JDKs, yes, I took advantage of that too.

jdk:
  - oraclejdk8
  - oraclejdk7
  - openjdk7

This is something that I didn’t do locally, so is a handy bonus for the build.

All told, I found this a useful experiment and exercise. And now I have a secondary build to help, and you can see the status of that build on Travis-CI.org