Friday, October 6, 2017

Asynchrouns and Transactional Event Listeners in Spring

The built-in event publication functionality exists from the early Spring versions and it is still useful for handling basic communication between Spring components in the same application context. In general, the application can generate application events (that can be arbitrary objects) and listen to them. The whole mechanism is really simple: using ApplicationPublisher you publish events and using EventListener you handle them. What I find especially useful is asynchronous and transactional event listeners.

Thursday, October 5, 2017

JUnit 5 - Quick Tutorial

JUnit 5 is the next generation unit testing framework for Java equipped with many interesting features including nested tests, parameterized tests, new extension API or Java 8 support to mentioned a few.

This article shows basic concepts of JUnit 5 including test lifecycle, parameter injection and assertions (basic, timeout and exception).

Documentation

First of all, JUnit 5 documentation is just great and in my opinion. Not only it contains comprehensive framework documentation, but also many examples including many samples. Don’t miss the documentation when learning JUnit 5: http://junit.org/junit5/docs/current/user-guide/

Dependencies

Firstly, JUnit 5 requires Java 8 to run. Finally. This brings the possibility to use Lambda expressions in tests and make them more consise (Lambda expressions are mainly used in assertions). Secondly, JUnit 5 consists of multiple artifacts grouped by JUnit Platform, JUnit Jupiter, and JUnit Vintage. This can sound scary, but today with tools such as Maven or Gradle this is not a problem at all and to get started you actually need a single dependency. The basic Gradle configuration could look like below:

buildscript {
    ext {
        junitPlatformVersion = '1.0.1'
        junitJupiterVersion = '5.0.1'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.junit.platform:junit-platform-gradle-plugin:${junitPlatformVersion}"
    }
}

apply plugin: 'java'
apply plugin: 'org.junit.platform.gradle.plugin'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies { 
    testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
}

task wrapper(type: Wrapper) {
    gradleVersion = '4.1'
}

JUnit 5 test classes and methods

The common test annotations used within a test class (imported from org.junit.jupiter.api) are:

  • @BeforeAll - executed before all methods in test lass
  • @BeforeEach - execute before each test method in test class
  • @Test - actual test method
  • @AfterEach - executed after each test method in test lass
  • @AfterAll - executed after all methods in test lass

Other basic but useful annotations:

  • @DisplayName - custom display name for test class or method
  • @Disabled - disabling test class or method
  • @RepeatedTest - make a test template out of the test method
  • @Tag - tag a test class or method for further test selection

A basic example:

import org.junit.jupiter.api.*;

@DisplayName("JUnit5 - Test basics")
class JUnit5Basics {

    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all tests (once)");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("Runs before each test");
    }

    @Test
    void standardTest() {
        System.out.println("Test is running");
    }

    @DisplayName("My #2 JUnit5 test")
    @Test
    void testWithCustomDisplayName() {
        System.out.println("Test is running");
    }

    @DisplayName("Tagged JUnit5 test ")
    @Tag("cool")
    @Test
    void tagged() {
        System.out.println("Test is running");
    }

    @Disabled("Failing due to unknown reason")
    @DisplayName("Disabled test")
    @Test
    void disabledTest() {
        System.out.println("Disabled, will not show up");
    }

    @DisplayName("Repeated test")
    @RepeatedTest(value = 2, name = "#{currentRepetition} of {totalRepetitions}")
    void repeatedTestWithRepetitionInfo() {
        System.out.println("Repeated test");
    }

    @AfterEach
    void afterEach() {
        System.out.println("Runs after each test");
    }
}

Note that test classes and methods does not need to be public - they can be package private.

Test Execution Lifecycle

In JUnit 5, by default a new test instance is created for each test method in a test class. This behaviour can be adjusted with class level @TestInstance annotation:

import org.junit.jupiter.api.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DisplayName("JUnit5 - Test lifecycle adjustments")
class JUnit5PerClassLifecycle {

    private Object first = new Object();
    private Object second;

    @BeforeAll
    void beforeAll() {
        this.second = this.first;
        System.out.println("Non static before all.");
    }

    @BeforeEach
    void beforeEach() {
        Assertions.assertEquals(first, second);
    }

    @Test
    void first() {
        Assertions.assertEquals(first, second);
    }

    @Test
    void second() {
        Assertions.assertEquals(first, second);
    }

    @AfterAll
    void afterAll() {
        System.out.println("Non static after all.");
    }

    @AfterEach
    void afterEach() {
        Assertions.assertEquals(first, second);
    }
}

In PER_CLASS mode a single test instance is created for all tests and @BeforeAll and @AfterAll methods does not need to be static anymore.

Parameter resolution

Test and callback methods can now take arguments like org.junit.jupiter.api.TestInfo, org.junit.jupiter.api.RepetitionInfo or org.junit.jupiter.api.TestReporter.

In addition, thanks to really simple yet powerful JUnit 5 extension API, resolving custom parameters in methods is a matter of providing own implementation of org.junit.jupiter.api.extension.ParameterResolver.

class JUnit5BuiltInParameterResolution {

    @BeforeAll
    static void beforeAll(TestInfo testInfo) {
        System.out.println("Before all can take parameters. Started: " + testInfo.getDisplayName());
    }

    @BeforeAll
    static void beforeAll(TestReporter testReporter) {
        testReporter.publishEntry("myEntry", "myValue");
    }

    @BeforeAll
    static void beforeAll(TestInfo testInfo, TestReporter testReporter) {
        testReporter.publishEntry("myOtherEntry", testInfo.getDisplayName());
    }


    @BeforeEach
    void beforeEach(TestInfo testInfo) {

    }

    @Test
    void standardTest(TestInfo testInfo) {

    }

    @DisplayName("Repeated test")
    @RepeatedTest(value = 2, name = "#{currentRepetition} of {totalRepetitions}")
    void repeatedTest(RepetitionInfo repetitionInfo) {
        System.out.println("Repeated test - " + repetitionInfo.toString());
    }

    @AfterAll
    static void afterAll() {

    }

    @AfterAll
    static void afterAll(TestInfo testInfo) {

    }

    @AfterEach
    void afterEach() {

    }
}

Assertions

JUnit 5 comes with many standard assertions that can be found in org.junit.jupiter.api.Assertions class.

Basic assertions

Basic assertions are: assertEquals, assertArrayEquals, assertSame, assertNotSame, assertTrue, assertFalse, assertNull, assertNotNull,assertLinesMatch, assertIterablesMatch

Example:

@Test
void basicAssertions() {
    // arrange
    List<String> owners = Lists.newArrayList("Betty Davis", "Eduardo Rodriquez");

    // assert
    assertNotNull(owners);
    assertSame(owners, owners);
    assertFalse(owners::isEmpty); // Lambda expression
    assertEquals(2, owners.size(), "Found owner names size is incorrect");
    assertLinesMatch(newArrayList("Betty Davis", "Eduardo Rodriquez"), owners);
    assertArrayEquals(
        new String[]{"Betty Davis", "Eduardo Rodriquez"}, 
        owners.toArray(new String[0])
    );
}

Assert all

Assertions.assertAll asserts that all supplied executables do not throw exceptions:

Assertions.assertAll(
    () -> Assertions.assertNotNull(null, "May not be null"),
    () -> Assertions.assertTrue(false, "Must be true")
);

The above will report multiple failures:

org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
    May not be null ==> expected: not <null>
    Must be true

Note: You may want to read about alternative in JUnit 4 and AssertJ - http://blog.codeleak.pl/2015/09/assertjs-softassertions-do-we-need-them.html

Timeout assertions

Timeout assertions are use in order to verify execution time of a task is not exceeded. There are two flavours of timeout assertion: assertTimeout and assertTimeoutPreemptively. Both are taking two

  • Execute the task synchronously, waiting for its completion and then asserts timeouts:
@Test
void assertTimeout() {
    // arrange
    Executable task = () -> Thread.sleep(1000);

    // waits for the task to finish before failing the test
    Assertions.assertTimeout(Duration.ofMillis(100), task::execute);
}

@Test
void assertTimeoutWithThrowingSupplier() {
    // arrange
    ThrowingSupplier<String> task = () -> "result";

    // waits for the task to finish before failing the test
    Assertions.assertTimeout(Duration.ofMillis(100), task::get);
}
  • Execute the task assynchronously (in a new thread), abort the execution when timeout reached:
@Test
void assertTimeoutPreemptively() {
    // arrange
    Executable task = () -> Thread.sleep(1000);

    // abort execution when timeout exceeded
    Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), task::execute);
}

@Test
void assertTimeoutPreemptivelyWithThrowingSupplier() {
    // arrange
    ThrowingSupplier<String> task = () -> "result";

    // abort execution when timeout exceeded, return the result
    String result = Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), task::get);

    Assertions.assertEquals("result", result);
}

Exception assertions

JUnit 5 built-in assertThrows gets expected exception type as first parameter and the executable (functional interface) potentially throwing an exception as the second. The method will fail if no exception or exception of different type is thrown. The method returns the exception itself that can be used for further assertions:

@Test
void assertException() {
    // arrange
    Executable throwingExecutable = () -> {
        throw new RuntimeException("Unexpected error!");
    };

    // act and assert
    RuntimeException thrown = Assertions.assertThrows(
        RuntimeException.class, throwingExecutable::execute, "???"
    );

    Assertions.assertAll(
        () -> Assertions.assertEquals("Unexpected error!", thrown.getMessage()),
        () -> Assertions.assertNotNull(thrown.getCause())
    );
}

Note: You may want to read about alternatives in JUnit 4 - http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html

Summary

JUnit 5 is packed with plenty features. In this article only basics were demonstrated but this should be enough for you to start writing your first JUnit 5 tests.

See also

Tuesday, October 3, 2017

Spring Boot - spring.config.name - Case Study

Externalizing Spring Boot application properties is useful when the same application code must be used with different configuration. If the configuration is to be kept away from the source code (which is considered a best practice anyways)spring.config.location environment property can be used to point the directory location with properties files for example. On the other hand, spring.config.name can be used to change the base name of the properties file which defaults to application. The documentation reads: if you don’t like application.properties as the configuration file name you can switch to another. But in what scenario spring.config.name could be used?

Thursday, September 28, 2017

Tuesday, September 12, 2017

Lombok - you should definitely give it a try

Lombok is not a new thing in a Java ecosystem, but I must admit I always underestimated its value until I tried it or I was “convienced” to try it. I did not see much value in adding a library that generates code that can be easily generated by any modern IDE these days. So I ignored the library and I have been writing or generating tons of boilerplate code. Not anymore. In 2016 I joined a Spring-based project where project Lombok was already in place. And since then I can’t work without Lombok anymore… Why?

So what is Lombok anyways?

Shortly speaking, Lombok is a Java library that generates tons of code for the developer by plugging in into the IDE and building tools. For example, instead of adding getters, setters, equals, hashCode and toString methods to POJOs, single [@Data](https://projectlombok.org/features/Data) annotation can be used.

Build tools support, like Gradle or Maven, does not bring issues

Lombok works with Gradle with no issues. You add compileOnly dependency on Lombok and that’s basically it:

compileOnly ("org.projectlombok:lombok:${lombokVersion}")

I did not expierience any issues with Maven neither, although I mainly work with Spring related projects and recently they all are Gradle based.

IntelliJ support is good enough

I am working with IntelliJ on a daily basis and its support for Lombok works just fine. Lombok is supported by 3rd party plugin: https://github.com/mplushnikov/lombok-intellij-plugin.

The configuration of the plugin is extremely easy: you need to enable Lombok plugin and annotation processing for the project. Of course, Lombok must be in the classpath. With project configured you can start importing Lombok annotations and start using them immediately in the source code.

I did not notice issues with code completion in IntelliJ. I did not notice any delays or missing features. When I want to display code definition for the generated method it shows me the Lombok annotation - which is fine - it would nice though to see the generated code.

On the negative side, sometimes it happens that the code is not immediately available - and then manual compilation needs to be executed. This is really rare in my case.

With Lombok enabled, some features cannot be reached directly from the code editor. For example, when using @Builder annotation a lot of code is generated, including the builder class. To find usage of certain builder methods you need to do this from the Structure view..

Navigating to symbols by name in generated code is not possible but this seems not an issue: when working with Lombok you know the generated code is related to certain classes. For example, UserBuilder is related to User class so you jump into the Userto see its builder (if you really need to).

All in all, on a daily basis there are no show stoppers as it goes to IntelliJ.

Reading the code is easier

One of the main advantages of using Lombok is less code that one needs to read. This is extremely useful during the code reviews - I open the class and I immediately see if it is a anemic @Data class or maybe a @Value object, if it provides @Builderetc. And although Lombok requires even more annotation in the source code (Lombok annotations, JPA annotations, Jackson annotations, Spring annotations …) it still makes the code more concise and easier to read / review.

Lombok standarizes (some) team practices

For example, before I started using Lombok, in every project there were several approaches to create builders . With Lombok it is much easier to maintain these practices (@Builder and @Singularity) .

Lombok works fine with other libraries

I did not expierience issues with JPA or Jakson annotations mixed with Lombok annotations. I have heard, though, about issues with MapStruct and Lombok in the past but it seems to be fixed now: (https://github.com/mapstruct/mapstruct/issues/510)

Lombok annotation can be easily used with Spring components so that less code is needed while creating. For example @AllArgsConstructor can be used to inject bean’s dependencies as Spring does not require contructors to be annotated with @Autowire:

@Service
@RequiredArgsContructor
class SomeService {
    private final Dep1 dep1;
    private final Dep2 dep2;
}

Worth noting (maybe) is the fact the Spring Boot Initializer (http://start.spring.io/) provides Lombok dependency in the generated project files (one of core dependencies to be added to your new project).

Consider Lombok for your next project

Lombok is a great library that speeds up the development, makes the code more concise, easier to read and maintain. Lombok seems mature enough to give it a try. Even if you decide to use only for simple cases it can bring a lot of value to your project. Believe me or not, but I was very sceptical about Lombok until I tried it for several weeks.

Friday, June 23, 2017

Remote debugging Wildfly application in IntelliJ

Remote debugging a Java application means connecting to the remotely running application using your local development environment. Java supports remote debugging out of the box: the target application must be executed with -agentlib:jdwp[=options] option which loads Java Debug Wire Protocol (jdwp) library that allows remote debugging using for example socket connection. In this short article you will learn how to get started with debugging web application deployed to Wildfly server by using IntelliJ.

Thursday, June 8, 2017

Cleaner parameterized tests with JUnit 5

The general idea of parameterized unit tests is to run the same test method for different data.
Creating parameterized tests in JUnit 4 is far from being perfect. There are many issues with the existing architecture: parameters are defined as class fields and constructor is needed to create them, parameterized and non-parameterized tests cannot be mixed in one test class and built-in data sources are very limited. Fortunately, all of this is improved in JUnit 5!