Kohei Nozaki's blog 

Entries tagged [test]

JUnit and Mockito tips


Posted on Friday Jul 03, 2020 at 06:40PM in Technology


In this entry I’ll share some tips about JUnit and Mockito for making unit tests better.

Mockito annotations

Mockito has some annotations that can be used for reducing redundancy of tests:

  • @Mock

  • @InjectMocks

  • @Captor

Before looking into the usage of those annotations, let’s assume we have the following production code which consists of 2 classes.

The first one is called MailServer, which has a method called send() that sends an SMTP message which this object receives as the parameter of the method. Note that the MailServer class most probably needs to be mocked out when you want to write a unit test for a class which uses the MailServer class because it really opens a TCP connection to an SMTP server, which is not a preferable thing for unit tests.

class MailServer {
    void send(String smtpMessage) throws IOException {
        // Opens a connection to an SMTP server, sends the SMTP message
    }
}

The other class is called Messenger, which depends on the MailServer class. This class requires an instance of the MailServer class in its constructor. This class has a method called sendMail(), which has 3 parameters. The responsibility of this method is first constructing an SMTP message based on those 3 parameters and then asking the MailServer object to send the SMTP message. It also does quick error handling which translates IOException into an unchecked one with embedding the content.

class Messenger {

    private final MailServer mailServer;

    Messenger(MailServer mailServer) {
        this.mailServer = mailServer;
    }

    void sendMail(String from, String to, String body) {
        String smtpMessage = String.join("\n", "From: " + from, "To: " + to, "", body);
        try {
            mailServer.send(smtpMessage);
        } catch (IOException e) {
            throw new UncheckedIOException("Error! smtpMessage=" + smtpMessage, e);
        }
    }
}

Let’s try writing a unit test for the Messenger class. But we don’t want to use the real MailServer class because it really tries to open a connection to an SMTP server. It will make testing harder because in order to test with the real MailServer class, we really need an SMTP server which is up and running. Let’s avoid doing that and try using a mocked version of a MailServer instance for the testing here.

A happy path test case would look like the following:

class MessengerPlainTest {

    MailServer mailServer;
    Messenger sut;

    @BeforeEach
    void setUp() {
        mailServer = Mockito.mock(MailServer.class);
        sut = new Messenger(mailServer);
    }

    @Test
    @DisplayName("Messenger constructs the SMTP message and feeds MailServer")
    void test() throws IOException {
        String expected = "From: joe@example.com\n"
                + "To: jane@example.com\n\n"
                + "Hello!";

        sut.sendMail("joe@example.com", "jane@example.com", "Hello!");

        Mockito.verify(mailServer).send(expected);
    }
}

In the setUp() method, a mock MailServer object is created and injected into the constructor of the Messenger class. And in the test() method, first we create the expected SMTP message which the Messenger class has to create, then we call the sendMail() method and finally we verify that the send() method of the mock MailServer object has been called with the expected SMTP message.

With annotations, the test above can be written as follows:

@ExtendWith(MockitoExtension.class)
class MessengerTest {

    @Mock
    MailServer mailServer;
    @InjectMocks
    Messenger sut;

    @Test
    @DisplayName("Messenger constructs the SMTP message and feeds MailServer")
    void test() throws IOException {
        String expected = "From: joe@example.com\n"
                + "To: jane@example.com\n\n"
                + "Hello!";

        sut.sendMail("joe@example.com", "jane@example.com", "Hello!");

        Mockito.verify(mailServer).send(expected);
    }
}

First we annotate the test class with @ExtendWith(MockitoExtension.class) (Note that it’s a JUnit5 specific annotation, so for JUnit4 tests we need something different). Having the test class annotated with that one, when there is a field annotated with @Mock in the test class, Mockito will automatically create a mock for the field and inject it. And when there is a field annotated with @InjectMocks, Mockito will automatically create a real instance of the declared type and inject the mocks that are created by the @Mock annotation.

This is especially beneficial when many mock objects are needed because it reduces the amount of repetitive mock() method calls and also removes the need for creating the object which gets tested and injecting the mocks into the object.

And also it provides a clean way to create a mock instance of a class which has a parameterized type. When we create a mock instance of the Consumer class, a straightforward way would be the following:

Consumer<String> consumer = Mockito.mock(Consumer.class);

The problem here is that it produces an unchecked assignment warning. Your IDE will complain about it and you will get this warning when the code compiles with -Xlint:unchecked :

Warning:(35, 49) java: unchecked conversion
  required: java.util.function.Consumer<java.lang.String>
  found:    java.util.function.Consumer

With the @Mock annotation, we can get rid of the warning:

@ExtendWith(MockitoExtension.class)
class MyTest {

    @Mock
    Consumer<String> consumer;
...

There is another useful annotation called @Captor. Let’s see the following test case:

@ExtendWith(MockitoExtension.class)
class MessengerCaptorTest {

    @Mock
    MailServer mailServer;
    @InjectMocks
    Messenger sut;

    @Captor
    ArgumentCaptor<String> captor;

    @Test
    @DisplayName("Messenger constructs the SMTP message and feeds MailServer")
    void test() throws IOException {
        sut.sendMail("joe@example.com", "jane@example.com", "Hello!");

        Mockito.verify(mailServer).send(captor.capture());
        String capturedValue = captor.getValue();
        assertTrue(capturedValue.endsWith("Hello!"));
    }
}

The @Captor annotation creates an object called ArgumentCaptor which captures a method parameter of a method call of a mock object. In order to capture a parameter with an ArgumentCaptor, first we need to call the capture() method in a method call chain of the Mockito.verify() method. Then we can get the captured value with the getValue() method and we can do any assertion against it. It’s especially useful in a situation where checking the equality is not sufficient and a complex verification is needed.

AssertJ

AssertJ is an assertion library for unit tests written in Java. It provides better readability and richer assertions than its older equivalents like the one shipped with JUnit. Let’s see some example code from the official website:

// entry point for all assertThat methods and utility methods (e.g. entry)
import static org.assertj.core.api.Assertions.*;

// basic assertions
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);

// chaining string specific assertions
assertThat(frodo.getName()).startsWith("Fro")
                           .endsWith("do")
                           .isEqualToIgnoringCase("frodo");

// collection specific assertions (there are plenty more)
// in the examples below fellowshipOfTheRing is a List<TolkienCharacter>
assertThat(fellowshipOfTheRing).hasSize(9)
                               .contains(frodo, sam)
                               .doesNotContain(sauron);

A unique feature of AssertJ is that all of the assertions here begin with the method assertThat() which receives the parameter that gets asserted. After that we specify the conditions the parameter needs to fulfill. An advantage of this approach is that we can specify multiple conditions with method call chain. It’s more readable and less verbose than the old way where repetitive assertTrue() or assertEquals() calls are involved. It also provides rich assertions for widely used classes like List, Set or Map.

Another useful feature of AssertJ is for verifying an unhappy path where an Exception is involved. Let’s remember the production code we used in the Mockito annotation section and consider a situation where the MailServer cannot connect to the SMTP server. Due to that, the send() method throws IOException. In this situation, the Messenger class is expected to catch the IOException and translate it into UncheckedIOException with the SMTP message embedded. A unit test for this can be written as follows with AssertJ:

@ExtendWith(MockitoExtension.class)
class MessengerUnhappyTest {

    @Mock
    MailServer mailServer;
    @InjectMocks
    Messenger sut;

    @Test
    @DisplayName("Messenger throws UncheckedIOException with the SMTP message when MailServer has thrown IOException")
    void test() throws IOException {
        doThrow(new IOException("The server is down")).when(mailServer).send(any());
        String expectedMessage = "From: joe@example.com\n"
                + "To: jane@example.com\n\n"
                + "Hello!";

        assertThatThrownBy(() -> sut.sendMail("joe@example.com", "jane@example.com", "Hello!"))
                .isInstanceOf(UncheckedIOException.class)
                .hasMessage("Error! smtpMessage=%s", expectedMessage)
                .hasCauseInstanceOf(IOException.class);
   }
}

First we make the mock MailServer instance throw IOException when its send() method is called. After that we pass a lambda expression which calls the sendMail() method to the assertThatThrownBy() method of AssertJ. After that we can do various assertions. What we are checking here is that the sendMail() method throws UncheckedIOException with the SMTP message embedded and it also contains a parent Exception whose class is IOException.

Conclusion

We’ve discussed some tips about Mockito and the basic uses of AssertJ for test cases that are written in JUnit. Both Mockito and AssertJ have extensive documents and rich functionality which greatly helps writing unit tests. I highly recommend checking the references below:

The pieces of code which are used in this entry can be found on GitHub: https://github.com/nuzayats/junittips


Jukito integration with JPA and guice-persist


Posted on Sunday Jul 31, 2016 at 11:28AM in Technology


A DI container such as Guice helps you to assemble loosely-coupled classes that easy to write unit tests.

But integration tests, that are necessary thing as well as unit tests, it’s a different story from writing unit tests. writing integration tests involve many cumbersome initialization code of frameworks such as DI container, JPA provider or an application server. they tend to spread across testcases and make testcases messy.

If you use Guice as DI container, Jukito helps you to write integration tests. its official documentation covers some simple usecases, but not mentioned about integration with guice-persist. so in this entry I’ll introduce you how to integrate and begin writing clean testcases without messy boilarplate code with them.

Create an application to be tested

Consider we have a simple JPA entity and a service class which uses it.

An entity class named Employee:

@Entity
public class Employee implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    public Employee(final String name) {
        this.name = name;
    }
...

The service class to be tested named EmployeeService:

public class EmployeeService {

    @Inject
    private EntityManager em;

    @Transactional
    public Long save(final String name) {
        final Employee employee = new Employee(name);
        em.persist(employee);
        em.flush();
        return employee.getId();
    }

    public List<String> findAllNames() {
        return em.createQuery("SELECT e.name FROM Employee e ORDER BY e.name", String.class).getResultList();
    }
}

Create a module for testing

Next, we will create a module for testing (BTW I recommend you to use Module overriding for creating one for testing, based on production one). this would be something like:

// Taken from https://gist.github.com/JWGmeligMeyling/785e459c4cbaab606ed8 , thanks!
public class DatabaseModule extends AbstractModule {

    @Override
    protected void configure() {
        install(new JpaPersistModule("myPU"));
        bind(JPAInitializer.class).asEagerSingleton();
    }

    @Singleton
    private static class JPAInitializer {
        @Inject
        public JPAInitializer(final PersistService service) {
            service.start();
        }
    }
}

Create JpaJukitoRunner

Then, create a special TestRunner which extends JukitoRunner as follows:

public class JpaJukitoRunner extends JukitoRunner {

    public JpaJukitoRunner(final Class<?> klass) throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException {
        super(klass);
    }

    public JpaJukitoRunner(final Class<?> klass, final Injector injector) throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException {
        super(klass, injector);
    }

    private UnitOfWork unitOfWork;

    @Override
    protected Object createTest() throws Exception {
        this.unitOfWork = getInjector().getInstance(UnitOfWork.class);
        this.unitOfWork.begin();
        return super.createTest();
    }

    @Override
    public void run(final RunNotifier notifier) {
        notifier.addListener(new RunListener() {

            @Override
            public void testFinished(final Description description) throws Exception {
                // this ensures every tests use distinct entity manager instances
                unitOfWork.end();
            }
        });
        super.run(notifier);
    }
}

This ensures every tests use distinct EntityManager instances for each execution. without this, only one EntityManager instance will be used for all of executions of test cases because it is stored in a ThreadLocal and JUnit uses only one Thread by default for all test executions.

That means that many entities will be kept managed during an execution. consider if you have thousands of test classes in your project - entities will be shared across all of test execution. it will make your EntityManager fat, also your tests may get affected by 1st level cache which got dirty by other test executions.

Create a testcase

Finally, you can write a testcase as follows:

@RunWith(JpaJukitoRunner.class)
@UseModules(DatabaseModule.class)
public class EmployeeServiceTest {

    @Inject
    private EmployeeService sut;
    @Inject
    private EntityManager em;

    @Before
    @Transactional
    public void setUp() throws Exception {
        em.createQuery("DELETE FROM Employee").executeUpdate();
    }

    @Test
    public void saveShouldPersistJohnDoe() throws Exception {
        final String name = "John Doe";

        final long id = sut.save(name);

        final Employee employee = em.find(Employee.class, id);
        assertThat(employee.getName(), is(name));
    }

    @Test
    public void findAllNamesShouldReturnExpectedResult() throws Exception {
        sut.save("Jane Doe");
        sut.save("John Doe");

        final List<String> result = sut.findAllNames();

        assertThat(result.size(), is(2));
    }
}

You can see that there are no any cumbersome initialization code of JPA or database stuff. and note that you can use declarative transaction management by @Transactional, for both the sut class and populating test data into your database.

Cleaning 1st level cache

I have mentioned about bad effect of 1st level cache of EntityManager earlier in this entry, so you may consider that you want to clean 1st level cache. you can do it with em.clear(), or also something like following:

@RunWith(JpaJukitoRunner.class)
@UseModules(DatabaseModule.class)
public class EmployeeServiceTestManagesUOW {

    @Inject
    private Provider<EmployeeService> sut;
    @Inject
    private Provider<EntityManager> em;
    @Inject
    private UnitOfWork unitOfWork;

    @Before
    @Transactional
    public void setUp() throws Exception {
        em.get().createQuery("DELETE FROM Employee").executeUpdate();
    }

    @Test
    public void saveShouldPersistJohnDoe() throws Exception {
        final String name = "John Doe";
        newEntityManager();

        final long id = sut.get().save(name);

        newEntityManager();
        final Employee employee = em.get().find(Employee.class, id);
        assertThat(employee.getName(), is(name));
    }

    private void newEntityManager() {
        unitOfWork.end();
        unitOfWork.begin();
    }
}

In this test, there are three distinct EntityManagers involved in a test execution. the one in setUp(), another one in invocation of sut#save() and finally one for em#find() which is used for assertion.

But in my opinion, this is an overkill and using one shared EntityManager for one test execution would be sufficient. if it didn’t work well, something may wrong with your usage of JPA.

Conclusion

We have seen how testcases which involve JPA and guice-persist could be written cleanly with Jukito. it enables us to eliminate cumbersome boilarplate code for managing and invoking Injector, JPA initialization and manual transaction management. now our testcases look pretty clean.

Executable testcases and the example project can be obtained from my GitHub repository.

References


Excluding particular JUnit test cases that marked as slow in the time of execution


Posted on Sunday Nov 01, 2015 at 03:43PM in Technology


Sometimes we need to create some slow test cases that involve some external resources such as databases, or external API servers. They are necessary to ensure that your application can integrate with such external resources while vast majority of test cases should stick with fast-running plain unit testing.

In such case, We usually wants to exclude such slow test cases from the ones that are frequently executed in local development environment so that we can get timely response from the tests. In this posting, I introduce you a solution that avoids maintenance of any hand-made listing of test cases.

Creating a suite that scans and runs all of test cases exist in classpath

First, assume we have a simple production class named Hello.

public class Hello {
    public String greetings(String name) {
        return name != null ? "hello, " + name : "hi, what's your name?";
    }
}

We also have a couple of test cases against the preceding class:

public class HelloTest1 {
    @Test
    public void test() {
        System.out.println("Running " + getClass().getSimpleName());
        Assert.assertEquals("hello, kyle", new Hello().greetings("kyle"));
    }
}

public class HelloTest2 {
    @Test
    public void test() {
        System.out.println("Running " + getClass().getSimpleName());
        Assert.assertEquals("hi, what's your name?", new Hello().greetings(null));
    }
}

Next, We’d like to introduce a test suite that automatically includes the preceding two test cases. Put a following dependency to your pom.xml:

<dependency>
    <groupId>io.takari.junit</groupId>
    <artifactId>takari-cpsuite</artifactId>
    <version>1.2.7</version>
    <scope>test</scope>
</dependency>

And create a test suite that named AllTests as follows. You can run this suite from your IDE or executing mvn -Dtest=AllTests test.

@RunWith(ClasspathSuite.class)
public class AllTests {
}

Involving a slow test case and exclude it

First, Create a marker interface which indicates that this test is slow:

public interface SlowTest {
}

Next create a slow test case which annotated with @Category(SlowTest.class) that we would like to avoid execute it frequently:

@Category(SlowTest.class)
public class HelloSlowTest {
    @Test
    public void test() throws Exception {
        System.out.println("Running " + getClass().getSimpleName());
        Thread.sleep(3000);
    }
}

Finally create a test suite that automatically excludes the test cases annotated as slow but executes rest of the test cases:

@RunWith(Categories.class)
@ExcludeCategory(SlowTest.class)
@SuiteClasses(AllTests.class)
public class AllExceptSlowTests {
}

You can run it on a daily basis instead of selecting root of your entire project and execute tests from your IDE or Maven without any hand maintenance of the listings of tests. For example, mvn -Dtest=AllExceptSlowTests test produces following output in very short-term execution time:

...
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Running category.suite.AllExceptSlowTests
Running HelloTest1
Running HelloTest2
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.084 sec
...

The complete resources can be obtained from https://github.com/lbtc-xxx/junit-category


How to bind / lookup DataSource via JNDI without container


Posted on Sunday Oct 25, 2015 at 10:58AM in Technology


While I prefer deploying JPA based apps to a Java EE container and test it via Arquillian as integration testing, some occasions won’t allow it and need arises that using a Servlet container or Java SE environment.

To supply information that required to connect the database (e.g. JDBC URL or credentials), it’s preferable to use JNDI rather than using DriverManager or javax.persistence.jdbc.* properties in persistence.xml because using JNDI eliminates the need of managing such information in the application codebase, also it enables to use the container managed connection pool which is more flexible and scalable over another.

In such case, hard-coded JNDI name of a DataSource may be a problem in the time of testing because JNDI lookup doesn’t work without container as is. So we may need some considering of involve pluggable mechanism of acquiring java.sql.Connection instance or creating persistence.xml for unit testing.

These solutions are not much difficult to implement, but it’s preferable if JNDI lookup does work without container as well because it will decrease amount of testing specific code. In this posting, I’ll give you a complete example of looking up a DataSource without container using bare InitialContext and the non-jta-datasource persistence descriptor definition.

Environment

  • tomcat-catalina artifact of Apache Tomcat 8.0.28: Enables binding a resource to JNDI context in Java SE environment

  • Apache Commons DBCP 1.4: Supplies BasicDataSource class so make the example in database independent manner

  • Apache Derby 10.12.1.1

  • EclipseLink 2.6.1

  • Oracle JDK8u60

Dependencies

<dependencies>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derby</artifactId>
        <version>10.12.1.1</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina</artifactId>
        <version>8.0.28</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

persistence.xml

Note that the non-jta-data-source is used with JNDI name of DataSource.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <non-jta-data-source>java:comp/env/jdbc/database</non-jta-data-source>
        <class>entity.Employee</class>
        <shared-cache-mode>NONE</shared-cache-mode>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="create"/>
            <property name="eclipselink.logging.level" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Employee.java

This is a simple JPA entity class that will be used in testing.

@Entity
public class Employee implements Serializable {
    @Id
    private Long id;
    private String firstName;
    private String lastName;

    // accessors omitted

Main.java

This binds a DataSource of Embedded in-memory Apache Derby database to java:comp/env/jdbc/database, then lookup it via InitialContext and EntityManagerFactory.

public class Main {
    private static final String JNDI = "java:comp/env/jdbc/database";

    public static void main(String[] args) throws Exception {
        bind();
        lookup();
        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
        populate(emf);
        query(emf);
    }

    private static void bind() throws NamingException {
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
        System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");

        final BasicDataSource ds = new BasicDataSource();
        ds.setUrl("jdbc:derby:memory:myDB;create=true");

        final Context context = new InitialContext();
        try {
            context.createSubcontext("java:");
            context.createSubcontext("java:comp");
            context.createSubcontext("java:comp/env");
            context.createSubcontext("java:comp/env/jdbc");
            context.bind(JNDI, ds);
        } finally {
            context.close();
        }
    }

    private static void lookup() throws NamingException, SQLException {
        final Context context = new InitialContext();
        try {
            final DataSource ds = (DataSource) context.lookup(JNDI);
            try (final Connection cn = ds.getConnection();
                 final Statement st = cn.createStatement();
                 final ResultSet rs = st.executeQuery("SELECT CURRENT_TIMESTAMP FROM SYSIBM.SYSDUMMY1")) {
                while (rs.next()) {
                    System.out.println(rs.getTimestamp(1));
                }
            }
        } finally {
            context.close();
        }
    }

    private static void populate(final EntityManagerFactory emf) {
        final EntityManager em = emf.createEntityManager();
        try {
            final EntityTransaction tx = em.getTransaction();
            tx.begin();
            final Employee emp = new Employee();
            emp.setId(1l);
            emp.setFirstName("Jane");
            emp.setLastName("Doe");
            em.persist(emp);
            tx.commit();
        } finally {
            em.close();
        }
    }

    private static void query(final EntityManagerFactory emf) {
        final EntityManager em = emf.createEntityManager();
        try {
            System.out.println(em.find(Employee.class, 1l));
        } finally {
            em.close();
        }
    }
}

Log

You can see the lookup() method dumped CURRENT_TIMESTAMP and EclipseLink successfully acquired a DataSource as follows.

2015-10-25 10:33:24.235
[EL Fine]: server: 2015-10-25 10:33:24.478--Thread(Thread[main,5,main])--Configured server platform: org.eclipse.persistence.platform.server.NoServerPlatform
[EL Config]: metadata: 2015-10-25 10:33:24.633--ServerSession(1323434987)--Thread(Thread[main,5,main])--The access type for the persistent class [class entity.Employee] is set to [FIELD].
[EL Config]: metadata: 2015-10-25 10:33:24.654--ServerSession(1323434987)--Thread(Thread[main,5,main])--The alias name for the entity class [class entity.Employee] is being defaulted to: Employee.
[EL Config]: metadata: 2015-10-25 10:33:24.656--ServerSession(1323434987)--Thread(Thread[main,5,main])--The table name for entity [class entity.Employee] is being defaulted to: EMPLOYEE.
[EL Config]: metadata: 2015-10-25 10:33:24.666--ServerSession(1323434987)--Thread(Thread[main,5,main])--The column name for element [firstName] is being defaulted to: FIRSTNAME.
[EL Config]: metadata: 2015-10-25 10:33:24.668--ServerSession(1323434987)--Thread(Thread[main,5,main])--The column name for element [lastName] is being defaulted to: LASTNAME.
[EL Config]: metadata: 2015-10-25 10:33:24.668--ServerSession(1323434987)--Thread(Thread[main,5,main])--The column name for element [id] is being defaulted to: ID.
[EL Info]: 2015-10-25 10:33:24.7--ServerSession(1323434987)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3
[EL Fine]: connection: 2015-10-25 10:33:24.706--Thread(Thread[main,5,main])--Detected database platform: org.eclipse.persistence.platform.database.JavaDBPlatform
[EL Config]: connection: 2015-10-25 10:33:24.714--ServerSession(1323434987)--Connection(1872973138)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
	platform=>JavaDBPlatform
	user name=> ""
	connector=>JNDIConnector datasource name=>java:comp/env/jdbc/database
))
[EL Config]: connection: 2015-10-25 10:33:24.715--ServerSession(1323434987)--Connection(1465346452)--Thread(Thread[main,5,main])--Connected: jdbc:derby:memory:myDB
	User: APP
	Database: Apache Derby  Version: 10.12.1.1 - (1704137)
	Driver: Apache Derby Embedded JDBC Driver  Version: 10.12.1.1 - (1704137)
[EL Config]: connection: 2015-10-25 10:33:24.715--ServerSession(1323434987)--Connection(1634387050)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
	platform=>JavaDBPlatform
	user name=> ""
	connector=>JNDIConnector datasource name=>java:comp/env/jdbc/database
))
[EL Config]: connection: 2015-10-25 10:33:24.716--ServerSession(1323434987)--Connection(1740223770)--Thread(Thread[main,5,main])--Connected: jdbc:derby:memory:myDB
	User: APP
	Database: Apache Derby  Version: 10.12.1.1 - (1704137)
	Driver: Apache Derby Embedded JDBC Driver  Version: 10.12.1.1 - (1704137)
[EL Info]: connection: 2015-10-25 10:33:24.747--ServerSession(1323434987)--Thread(Thread[main,5,main])--/file:/Users/kyle/src/jndi-se/target/classes/_myPU login successful
[EL Fine]: sql: 2015-10-25 10:33:24.784--ServerSession(1323434987)--Connection(762809053)--Thread(Thread[main,5,main])--CREATE TABLE EMPLOYEE (ID BIGINT NOT NULL, FIRSTNAME VARCHAR(255), LASTNAME VARCHAR(255), PRIMARY KEY (ID))
[EL Fine]: sql: 2015-10-25 10:33:24.85--ClientSession(1027495011)--Connection(1688470144)--Thread(Thread[main,5,main])--INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME) VALUES (?, ?, ?)
	bind => [1, Jane, Doe]
[EL Fine]: sql: 2015-10-25 10:33:24.877--ServerSession(1323434987)--Connection(640808588)--Thread(Thread[main,5,main])--SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID = ?)
	bind => [1]
Employee{id=1, firstName='Jane', lastName='Doe'}

The complete source code can be obtained from my GitHub repository.


Lean example of integration test Maven project for WildFly


Posted on Monday Feb 23, 2015 at 11:20PM in Technology


I created similar example before, but it was redundant. I created more lean version so leave here with some notes. check my GitHub repository for details.

The project contains AppServer class, which extends ExternalResource so it can be used with @Rule annotation of JUnit as follows. note that mavenit is the name of WAR file to be tested.

public class HelloImplIT {

    @ClassRule
    public static AppServer appServer = new AppServer();
    private static Hello sut;

    @BeforeClass
    public static void beforeClass() {
        sut = appServer.lookup("mavenit", HelloImpl.class, Hello.class);
    }

    @Test
    public void test() {
        Assert.assertEquals("Hello world!", sut.hello());
    }
}

The project is easy to use with both of IDE and standalone. to run IT classes with IDE, you need to launch the application server, deploy the project as WAR package, then run a IT class from IDE. if you launched the server at not 8080 port, specify the port in app-server.port system property.

To run IT classes in standalone Maven, use following command. it automatically launches WildFly instance with port offset of 30000, deploy the WAR file, running IT classes, undeploy the WAR and stops WildFly. the command is intended to use from a Jenkins job.

mvn verify -Pintegration-test-with-wildfly \
 -Djava.home=/Library/Java/JavaVirtualMachines/jdk8/Contents/Home/jre \
 -Djboss-as.home=/Users/kyle/servers/wildfly-8.2.0.Final \
 -Dwildfly.port=39990 \
 -Dapp-server.port=38080 \
 -Dwildfly.jvmArgs="-Djboss.server.base.dir=/Users/kyle/servers/wildfly-8.2.0.Final/standalone-mavenit -Djboss.socket.binding.port-offset=30000 -ea"

You can configure following parameters through command line argument:

  • JAVA_HOME-Djava.home

  • WildFly distribution ⇒ -Djboss-as.home

  • jboss.server.base.dir ⇒ inside -Dwildfly.jvmArgs

  • Port offset ⇒ -Djboss.socket.binding.port-offset inside -Dwildfly.jvmArgs. you need to set -Dwildfly.port and -Dapp-server.port accordingly.