Recently I stumbled on great video about testing on Java EE, and it’s like completed the puzzle about how to perform testing on Java EE in my case. In software development, testing was something important as the code itself, if you want to deliver a good and robust software then you must test your software before deliver it. Testing it’s not only doing by tester or quality assurance team, but as a programmer we also need to create a test to make sure our software is reliable in any condition and to make sure that what are you build is already the right thing.

To summarize, as developer there is two or three type of testing that should you know they are unit testing, integration testing, and maybe system testing.

Unit Test: Mostly focus on the smallest unit of the business code which is tend to focus on single class. In this test you don’t need to run a container, just execute some code to test the business logic code.

Integration Test: The opposite of unit test, integration was use to test the whole software which is you need a Java EE environment to do this. In this test you combine several components for example, EJB, JPA, CDI and many Java EE API which is need a container, a real environment like.

System Test: Unit and integration test was good, but sometimes you need to test the software in real environment. Including application server, database, server configuration which is the only different it’s not the real production server.

In my opinion I agree that good test it must be fast, reliable and easy to write and maintain. So more smaller the test it’s more easy to write and maintain, but sure it’s far away from real world application. In another case to just test business logic code that need to invoke a container it’s to overrated. I more prefer to write more unit testing, less integration test and more prefer doing system test, but it’s not mean you can’t test your EJB or many Java EE API with unit test at least you can Mock it. With this you still achieve the fast feedback from unit test, and to have system test to test the whole system is much better rather than using a container since we bring the real environment.

Unit Testing

Maven already included unit testing on the default of life-cycle bindings which means unit testing is important enough to made your application not build when the test fail. To perform unit testing you need a Junit, Hamcrest, and Mockito. Those three frameworks was really helpful and I will give you an example why you really need those frameworks. For example to test a simple business logic code.

public class Tax {

    private static final BigDecimal PERCENTAGE_TAX;

    static {
        PERCENTAGE_TAX = new BigDecimal("0.10");
    }

    public BigDecimal priceWithTax(BigDecimal price, boolean isTaxIncluded) {
        if (isTaxIncluded) {
            return price;
        } else {
            BigDecimal tax = price.multiply(PERCENTAGE_TAX);
            return price.add(tax);
        }
    }
}

From code above you can see the purpose was check if the tax was included on price you not need to do anything, but if the tax was not included you need to add the price with 10% from the actual price. This is a simple business logic code which can be test with unit testing.

public class TaxTest {

    Tax tax;

    @Before
    public void setUp() {
        this.tax = new Tax();
    }

    @Test
    public void shouldTestTaxIncluded() {
        BigDecimal price = new BigDecimal("1000");
        boolean isTaxIncluded = true;

        BigDecimal expected = this.tax.priceWithTax(price, isTaxIncluded);

        assertThat(expected, is(equalTo(price)));
    }

    @Test
    public void shouldFailedWhenTaxNotIncluded() {
        BigDecimal price = new BigDecimal("1000");
        boolean isTaxIncluded = false;

        BigDecimal expected = this.tax.priceWithTax(price, isTaxIncluded);

        assertThat(expected, is(not(equalTo(price))));
    }
}

I just shown you a simple test for a business logic which can be done only with Junit and Hamcrest, but then how you can test a CDI, EJB, or any others Java EE API? There is come Mockito, with Mockito you can mocking the beans and perform simple and fast test without any container needed to start. For example you have an EJB Class for creating, remove, and find all books in your shop.

@Stateless
public class BookShop {

    @PersistenceContext(name = "bookshopPU")
    EntityManager em;

    @Inject
    Tax tax;

    @Inject
    Logger log;

    public List<Book> findAllBook() {
        log.info("Find All Books");
        return this.em.createNamedQuery(Book.FIND_ALL).getResultList();
    }

    public Book findBookById(Long id) {
        log.info("Find Book by ID");
        return this.em.find(Book.class, id);
    }

    public void addBookStock(Book book) {
        log.info("Create New Book");
        this.em.persist(book);
    }

    public void removeBookStock(Book book) {
        log.info("Remove New Book");
        this.em.remove(book);
    }

    public JsonObject getBookOrder(Long id, URI self) {
        log.info("Check New Order from Specific Book");
        Book book = findBookById(id);
        return Json.createObjectBuilder()
                .add("isbn", book.getIsbn())
                .add("title", book.getTitle())
                .add("price", tax.priceWithTax(book.getPrice(), book.isTaxIncluded()))
                .add("_links", Json.createObjectBuilder()
                        .add("rel", "self")
                        .add("href", self.toString())
                )
                .build();
    }
}

Ok, there is something I want you to take a notes from EJB class above. First, I’m not using an interface local or remote I just using no-interface view and which is remove a lot of plumbing code from EJB and it’s great. Second, I’m not using a private variable for tax and log variable, some of you maybe said that I broke the Encapsulation Rule, but actually I’m not. The variable was annotated with @Inject and the container will provide the beans with a proxy, but it will be a different if I provide a getter and setter method because actually it will broke the Encapsulation Rule even I made it as private.

The benefit of having a public variable is it will made your test class more easier, because you can directly create new beans from EJB class and it can’t be done when you marked the variable as private.

@Before
public void setUp() {
    this.bookShop.tax = new Tax();
}

Now, rather than create a new bean let’s start to using Mockito to save your time on write a test. Because with Mockito you can fully control your test code, and here is the example of the test code.

public class BookShopTest {

    private static final Long ID = 1L;

    BookShop bookShop;

    @Before
    public void setUp() {
        this.bookShop = new BookShop(); // Tested class, so don't mock it.
        this.bookShop.em = mock(EntityManager.class);
        this.bookShop.log = mock(Logger.class);
    }

    @Test
    public void shouldGetListOfBooks() {
        List<Book> books = new ArrayList<>();

        Query mockedQuery = mock(Query.class);
        when(mockedQuery.getResultList()).thenReturn(books);
        when(mockedQuery.setParameter(
                Matchers.anyString(), Matchers.anyObject())
        ).thenReturn(mockedQuery);
        when(this.bookShop.em.createNamedQuery(Book.FIND_ALL))
                .thenReturn(mockedQuery);

        books = this.bookShop.findAllBook();

        assertThat(books, is(not(nullValue())));
    }

    @Test
    public void shouldGetAllBooks() {
        List<Book> books = new ArrayList<>();

        Book book = mock(Book.class);
        when(book.getId()).thenReturn(8L);

        books.add(book);

        Query mockedQuery = mock(Query.class);
        when(mockedQuery.getResultList()).thenReturn(books);
        when(mockedQuery.setParameter(
                Matchers.anyString(), Matchers.anyObject())
        ).thenReturn(mockedQuery);
        when(this.bookShop.em.createNamedQuery(Book.FIND_ALL))
                .thenReturn(mockedQuery);

        books = this.bookShop.findAllBook();

        assertThat(books.size(), is(1));
    }

    @Test
    public void shouldGetBookById() {
        Book expected = new Book();

        when(this.bookShop.em.find(Matchers.anyObject(), Matchers.anyLong()))
                .thenReturn(expected);

        Book actual = this.bookShop.findBookById(ID);

        assertThat(actual, is(equalTo(expected)));
    }

    @Test
    public void shouldRemoveBook() {
        Book book = new Book();
        /**
         * doNothing(), doAnswer(), doThrow() used to test void method, the
         * format: doNothing().when(bean).method_name();
         */
        doNothing().when(this.bookShop.em).remove(Matchers.anyObject());

        this.bookShop.removeBookStock(book);

        verify(this.bookShop.em).remove(book);
    }

    @Test
    public void shouldSaveBook() {
        Book book = new Book();

        doNothing().when(this.bookShop.em).persist(Matchers.anyObject());

        this.bookShop.addBookStock(book);

        verify(this.bookShop.em).persist(book);
    }

}

Integration Test

Sometimes you can’t just simple using unit test and then there is come Integration Test. Integration Test it’s mean integrate your code with a container (in this case is application server, database, internet connection, etc.) and you can recognize this kind of test easily, when you can’t just run the test class without starting something then the test was classified as integration test.

For example, you want to test some Java EE API that can’t be mocked like for example JPA API. You need to test is the entity class mapping correctly to the database. I will give example for the entity class would be like this.

@Entity
@Table(name = "book")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@NamedQueries(
        @NamedQuery(name = Book.FIND_ALL, query = "select b from Book b")
)
public class Book {

    public static final String FIND_ALL = "Book.FindAll";

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlTransient
    private Long id;

    @NotNull
    private String isbn;

    @NotNull
    private String title;

    @NotNull
    private BigDecimal price;

    @NotNull
    @XmlElement(name = "tax_included")
    private boolean isTaxIncluded;

    /* getter and setter method */
}

To perform test for JPA API you need to add database driver and ORM provider dependency. I will used EclipseLink as ORM provider and Derby for the database (of course you can choose Hibernate and H2 database if you more familiar with it) and don’t forget to make the scope as test since we not need the dependency included beside of test life cycle.

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.5.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derby</artifactId>
    <version>10.10.2.0</version>
    <scope>test</scope>
</dependency>

Next, we need to made a persistence.xml files for testing purpose put it on src/test/resources/META-INF directory and since we will using a local database we can use resource local transaction type, remember to not use resource local on your server.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="integration-test" transaction-type="RESOURCE_LOCAL">
        <!-- Make sure to include all of your JPA class -->
        <class>id.swhp.javaee.testing.bookshop.entity.Book</class>
        <!-- below was configuration for Embeded Derby database -->
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:./example;create=true"/>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
        </properties>
    </persistence-unit>
</persistence>

With this, you can started to write integration test for JPA API. Mainly the test class will test your entity class I would give a simple example about create a new entity, the test class will be like this.

public class BookIT {

    EntityManager em;
    EntityTransaction tx;

    @Before
    public void setUp() {
        this.em = Persistence.createEntityManagerFactory("integration-test")
                .createEntityManager();
        this.tx = this.em.getTransaction();
    }

    @After
    public void tearDown() {
        this.em.clear();
        this.em.close();
    }

    @Test
    public void validateORMMapping() {
        Book book = new Book();
        book.setIsbn("12345");
        book.setPrice(new BigDecimal("1000"));
        book.setTitle("Lorem Ipsum");
        book.setIsTaxIncluded(false);

        this.tx.begin();
        this.em.merge(book);
        this.tx.commit();
    }
}

Sometimes you need a container to test another Java EE API, because it’s impossible to be mock out. For example an InjectionPoint interface while you made a logger producer, especially when it’s using Produces annotations which is need a container.

@Singleton
public class LoggerProducer {

    @Produces
    public Logger produceLogger(InjectionPoint ip) {
        return Logger.getLogger(ip.getMember().getDeclaringClass().getName());
    }
}

First, you need to add Arquillian dependency on your pom.xml.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>1.1.13.Final</version>
            <scope>import</scope>
            <type>pom</type>
         </dependency>
    </dependencies>
</dependencyManagement>

    <dependencies>
        ....
        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <version>1.1.13.Final</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.weld</groupId>
            <artifactId>weld-core</artifactId>
            <version>2.4.2.Final</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
            <version>1.0.0.CR9</version>
            <scope>test</scope>
        </dependency>
        ....
</dependencies>

I will give a little explanation about the Arquillian dependency, first you need to put the parent of Arquillian bom dependency on <dependencyManagement> then you can start to add more Arquillian dependency for example arquillian-junit-container which is junit that wrapped by Arquillian.

Next we need to specify the container, and since Arquillian selects the target container based on which container adapter is available on the test classpath. That means we’ll be adding more libraries to the project. An Arquillian test can be executed in any container that is compatible with the programming model used in the test (as long as the container has an Arquillian adapter). Our test is using the CDI programming model, so you need to use any container to supports CDI you can start with the Weld EE embedded container.

Before you write an integration test for logger producer you need to write a Class that will provide the logger.

public class LoggerInjectionSupport {

    @Inject
    Logger log;

    public Logger getLogger() {
        return log;
    }
}

Finally, you can start to write your integration test like this.

@RunWith(Arquillian.class)
public class LoggerProducerIT {

    @Inject
    LoggerInjectionSupport cut;

    @Deployment
    public static WebArchive create() {
        return ShrinkWrap.create(WebArchive.class)
                .addClasses(LoggerProducer.class, LoggerInjectionSupport.class)
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Test
    public void shouldProduceLogger() {
        Logger log = this.cut.getLogger();

        String expected = this.cut.getClass().getName();
        String actual = log.getName();

        assertThat(actual, is(equalTo(expected)));
    }
}

You can see that I made an Archive which will be an Web Arhcive (WAR), in Arquillian you can specify what kind of Java Archive and what kind of classes that want to be included.

System Test

System test was more likely a job for tester or quality assurance team, because the meaning of system test was to perform a real life environment test (of course not in production, but more like a copy of production environment). You perform test for the REST endpoint or the Website itself, the video shown clearly how to do the system test and in my opinion it’s not much necessary for a programmer, but it will be another story if you’re on small and new company that only consist programmer and without a tester or quality assurance team, then I encourage you to learning a lot about system test.

References: