FEST Assert - a fluent interface for assertions

Filed under: Java, TDD, Test automation, — Tags: Bottom up, FEST Assert, Fluent assertions, Hamcrest, Hardcoded database, In memory database, Top down, assertThat — Thomas Sundberg — 2011-04-24

Hamcrest is a great framework for assertThat and it is bundled with JUnit. It is getting some competition from another framework, the FEST assertThat framework. The idea behind FEST is to use a fluent interface. This means that you can use your development environments code completion features to build your asserts. Its main goal is to improve test code readability and make maintenance of tests easier.

I created a small example just to compare the two frameworks.

The idea is that we want to develop a system and we know that it will need some kind of persistence. We are currently not sure about the database design. It will have to emerge from the demands from the layers above. We will build the system top down instead of bottom up. We want to automate the testing of the system and the execution of all tests has to be very fast. Therefore we need an in memory database that is extremely easy to alter.

One solution is to hard code the data layer during the development which means that we will always know the state of the persistence layer at any given time and we are able to add data from our development environment.

With a hardcoded data layer during development, changing it to a real database is just about replacing the fake solution with a real database and test drive it with some integration tests. This is, however, out of the scope today.

When we enter the story it has emerged that we need to store cars in our persistence layer. A car is a really simple data transfer object, dto, with just a few fields:

src/main/java/se/sigma/fest/hamcrest/comparison/dto/Car.java

package se.sigma.fest.hamcrest.comparison.dto;

public class Car {
    private String registrationNumber;
    private String brand;
    private String color;

    public String getRegistrationNumber() {
        return registrationNumber;
    }

    public void setRegistrationNumber(String registrationNumber) {
        this.registrationNumber = registrationNumber;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

We will manipulate our cars using a data access layer. It will be implemented using an interface so a fake solution can be replaced at any time. The interfaces is implemented as:

src/main/java/se/sigma/fest/hamcrest/comparison/dao/CarDao.java

package se.sigma.fest.hamcrest.comparison.dao;

import se.sigma.fest.hamcrest.comparison.dto.Car;

import java.util.Collection;

public interface CarDao {
    void add(Car car);

    Car getCar(String registrationNumber);

    Collection<Car> getAllCars();

    void update(Car car);

    void delete(String registrationNumber);
}

The entire system will be built using Maven as build system and all production code will be test driven using JUnit and an assertThat framework. The tests will be written twice to enable a comparison between Hamcrest and FEST is possible. The Maven pom that will make this possible is:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>se.sigma.educational</groupId>
    <artifactId>fest-assert-example</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
        </dependency>
        <dependency>
            <groupId>org.easytesting</groupId>
            <artifactId>fest-assert</artifactId>
            <version>1.4</version>
        </dependency>
    </dependencies>
</project>

Comparison

The Hamcrest implementation looks like this:

src/test/java/se/sigma/comparison/hamcrest/CarDaoTest.java

package se.sigma.comparison.hamcrest;

import org.junit.Test;
import se.sigma.fest.hamcrest.comparison.dao.CarDao;
import se.sigma.fest.hamcrest.comparison.dao.CarDaoFake;
import se.sigma.fest.hamcrest.comparison.dto.Car;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class CarDaoTest {

    @Test
    public void addCar() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();

        carDao.add(car);

        assertThat(carDao.getCar(car.getRegistrationNumber()), is(car));
    }

    @Test
    public void getAllCars() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();

        carDao.add(car);

        assertThat(carDao.getAllCars().contains(car), is(true));
    }

    @Test
    public void updateCar() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();

        carDao.add(car);
        String brown = "Brown";
        car.setColor(brown);

        carDao.update(car);

        assertThat(carDao.getCar(car.getRegistrationNumber()).getColor(), is(brown));
    }

    @Test
    public void deleteCar() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();
        carDao.add(car);
        assertThat(carDao.getAllCars().contains(car), is(true));

        carDao.delete(car.getRegistrationNumber());

        assertThat(carDao.getAllCars().contains(car), is(false));
    }

    private Car createBlackChrysler() {
        Car car = new Car();
        car.setRegistrationNumber("XOE546");
        car.setBrand("Chrysler");
        car.setColor("Black");
        return car;
    }
}

The FEST-Assert implementation looks like this:

src/test/java/se/sigma/comparison/fest/CarDaoTest.java

package se.sigma.comparison.fest;

import org.junit.Test;
import se.sigma.fest.hamcrest.comparison.dao.CarDao;
import se.sigma.fest.hamcrest.comparison.dao.CarDaoFake;
import se.sigma.fest.hamcrest.comparison.dto.Car;

import static org.fest.assertions.Assertions.assertThat;

public class CarDaoTest {

    @Test
    public void addCar() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();

        carDao.add(car);

        assertThat(carDao.getCar(car.getRegistrationNumber())).isEqualTo(car);
    }

    @Test
    public void getAllCars() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();

        carDao.add(car);

        assertThat(carDao.getAllCars()).contains(car);
    }

    @Test
    public void updateCar() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();

        carDao.add(car);
        String brown = "Brown";
        car.setColor(brown);

        carDao.update(car);

        assertThat(carDao.getCar(car.getRegistrationNumber()).getColor()).matches(brown);
    }

    @Test
    public void deleteCar() {
        CarDao carDao = new CarDaoFake();
        Car car = createBlackChrysler();
        carDao.add(car);
        assertThat(carDao.getAllCars()).contains(car);
        assertThat(car).isIn(carDao.getAllCars());
        carDao.delete(car.getRegistrationNumber());

        assertThat(car).isNotIn(carDao.getAllCars());
    }

    private Car createBlackChrysler() {
        Car car = new Car();
        car.setRegistrationNumber("XOE546");
        car.setBrand("Chrysler");
        car.setColor("Black");
        return car;
}
    }

Faked database implementation

The fake implementation of the data layer may look like this:

src/test/java/se/sigma/fest/hamcrest/comparison/dao/CarDaoFake.java

package se.sigma.fest.hamcrest.comparison.dao;

import se.sigma.fest.hamcrest.comparison.dto.Car;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class CarDaoFake implements CarDao {
    private static Map<String, Car> cars = new HashMap<String, Car>();

    public void add(Car car) {
        cars.put(car.getRegistrationNumber(), car);
    }

    public Car getCar(String registrationNumber) {
        return cars.get(registrationNumber);
    }

    public Collection<Car> getAllCars() {
        return cars.values();
    }

    public void update(Car car) {
        cars.put(car.getRegistrationNumber(), car);
    }

    public void delete(String registrationNumber) {
        cars.remove(registrationNumber);
    }
}

Conclusion

Hamcrest and FEST reads differently. Try them both and use the best in your project.

Resources



(less...)

Pages

About
Events
Why

Categories

Agile
Automation
BDD
Clean code
Continuous delivery
Continuous deployment
Continuous integration
Cucumber
Culture
Design
Executable specification
Gradle
Guice
J2EE
JUnit
Java
Linux
Load testing
Maven
Mockito
Pair programming
PicoContainer
Presentation
Programming
Public speaking
Quality
Recruiting
Requirements
Scala
Selenium
Software craftsmanship
Software development
Spring
TDD
Teaching
Technical debt
Test automation
Tools
Web
Windows
eXtreme Programming

Authors

Thomas Sundberg
Adrian Bolboaca

Archives

Meta

rss RSS