Tag: maven

Recently, I had a task to migrate the unit tests in our project from ‘JUnit 4’ to ‘JUnit 5’. As many developers, I researched a bit to learn about the major differences between the two versions and drafted a plan for smooth migration.

From the first look, I thought my only job was refactoring the tests and probably some helper classes. But, I was wrong! I ran into a configuration issue with the maven-surefire-plugin configuration.

In this post, I will be sharing the encountered issue and its fix. Note that I will not cover the detailed steps of how to migrate from ‘JUnit 4’ to ‘JUnit 5’.

Tests run: 0!

We, as many other developers, use the maven-surefire-plugin to run our tests during the test phase of maven’s build lifecycle. We rely heavily on this plugin because it fails the build when one of the tests is broken!

With JUnit4, everything was working perfectly! But after the migration, the plugin was always reporting that not tests are run:

'Tests run: 0, Failures: 0, Errors: 0, Skipped: 0 ...'!

Calculator Class

For the purpose of this blog, let us assume we want to build a Calculator. For now, we only have the ‘add‘ method implemented as shown below.

Dev Tools: Configuring some dev tools on their machines was the second step. This involved the installation and configuration of Java, IntelliJ, Maven and Perforce. Some of those tools such as Perforce and Maven were relatively new to them; so they took some time to learn more about it.

TDD: By now, they were ready to write some code! And what would be better than following TDD to do that? Most of our teams started adopting TDD, thus coaching newcomers on TDD for simple dev problems is a must! For that purpose I picked the following two problems:

Mars Rover: This might be an easy problem, but I find it well suited to practice TDD especially for TDD newbies as it has a lot of cases to be covered by tests.

Coffee Machine: The beauty of this problem, is that it simulates what happens in the life cycle of an agile project, such as:

Defining new requirements at the start of each iteration

Writing the minimum code to implement the required features

Continuous code refactoring

Write the sufficient tests at each iteration

Design Pattern and Code Refactoring: The two problems above may not be complex and can be solved in a short time, but the solution wasn’t the primary purpose rather it was introducing new concepts and practices to them. To make sure this purpose was achieved, I was performing multiple code review sessions during each iteration and suggesting enhancement at each time. This process elongated the time for each iteration, but it was worth. Some of the concepts I focused on were:

Test coverage

Builder pattern

Visitor pattern

Factory pattern

Bad and good code practices

Mocking

Maven: They used Maven to build the code they wrote previously, but it was only maven’s basic commands. At this phase of the training, I asked them to dig deeper into maven to have a better understanding how it works; mainly focusing on:

Phases of build lifecycle

Dependency management

Plugins

Local and remote repositories

SCM: Whether it is Git or Perforce, there are a couple of must know operations for any developer to be part of a development team. As a practice on those operations, they simulated a real dev cycle scenario by:

Sharing a common working directory on Perforce

Creating branches

Merging/Integrating changes

Resolving conflicts

Continuous Integration (CI)As fresh graduates, the continuous integration was a new concept for them. Whereas for us, it is an essential process of our development cycle. It wasn’t possible to use an existing Jenkins instance to perform their testing; thus they executed the below steps:

Download and configure Jenkins locally on their machines

Submit their code to Perforce

Add a new job that syncs, compile code and execute the tests

I noticed the benefit of this training from the emails they sent me at the end of the program. They detailed what they learned and most importantly they were able to highlight the advantages of those practices and tools.

How should we test the Data Access Layer code?

Many developers ask that question. Similar to the other layers of your system, it should be fully tested to prevent unexpected and random behavior in production. There are many ways to achieve that, among of which are mocks or in-memory database.

The problem with mocks is that instead of testing the validity of your SQL queries (syntax and execution), you will only be testing the validity of the system’s flow. On the other hand, using the in-memory database will validate both! That is why I prefer it over mocking. But, you should keep in mind that the SQL syntax might differ from one database engine to another.

In this blog, I will be giving an example of using “H2 In-Memory” in unit tests. The code of this example is available on my GitHub account.

H2 In-Memory in Action

So, let us see H2 in action 🙂

For the sake of this blog, I will assume we want to test three SQL operations on the table “Members” having the following model:

MEMBERS
ID | NAME |
INTEGER | VARCHAR(64) |

The SQL operations to be covered in this blog are:

Create Table

Insert (batch of prepared statements)

Select *

Code Explanation

The example will be based on five files (pom.xml, Member.java, SqlRepository.java, H2Repository.java and H2MembersRepositoryTest). In this section, I will give a brief explanation of each file.

In this class, we establish a connection to our database. What is important in this class is that we pass the connection string as a parameter to the constructor thus making our code unbounded to any specific database engine (MySql, H2, Sybase, Oracle, etc.). This will make writing our tests much easier!

The class consists of:

Constructor: initializes an instance of SQL Connection using the connection string passed as parameter

Three public methods:

createTable: executes an update query to create the”MEMBERS” table.

allMemebers: executes a select query and returns the found records in a list of Members.

insertMembers: takes a list of “Member” as a parameter and inserts the values into the “MEMBERS” table.

I added this class under “Test Sources Root” because it is only used by the tests.

As you notice, it extends the SqlRepository class implemented previously. Thus, we don’t have a lot to implement here. The only method added is a new method “closeConnection” that drops all the existing tables from the database.

You might wonder why would we need that since we are using an In-Memory database. That might be true for this simple example, but it will be a necessity when running multiple tests classes. That is because, in Java, all the tests are run in the same JVM which means that the H2 instance initialized in the first test will be shared with the next test classes. This approach might lead to an unexpected behavior when using the same tables in the different test classes.

This is the simple test class! Our single test (it_correctly_inserts_members_to_a_database) is invoking the three methods we implemented before (createTable, insertMember and allMembers). If any of those methods is badly written our test would fail.