Category Archives: Testing

mock Spring bean, encapsulate spring bean

How to mock Spring bean (version 2)

EDIT: As of Spring Boot 1.4.0, faking of Spring Beans is supported natively via annotation @MockBean. Read Spring Boot docs for more info.

About a year ago, I wrote a blog post how to mock Spring Bean. Patterns described there were little bit invasive to the production code.  As one of the readers Colin correctly pointed out in comment, there is better alternative to spy/mock Spring bean based on @Profile annotation. This blog post is going to describe this technique. I used this approach with success at work and also in my side projects.

Note that widespread mocking in your application is often considered as design smell.

Introducing production code

First of all we need code under test to demonstrate mocking. We will use these simple classes:

@Repository
public class AddressDao {
	public String readAddress(String userName) {
		return "3 Dark Corner";
	}
}

@Service
public class AddressService {
	private AddressDao addressDao;
	
	@Autowired
	public AddressService(AddressDao addressDao) {
		this.addressDao = addressDao;
	}
	
	public String getAddressForUser(String userName){
		return addressDao.readAddress(userName);
	}
}

@Service
public class UserService {
	private AddressService addressService;

	@Autowired
	public UserService(AddressService addressService) {
		this.addressService = addressService;
	}
	
	public String getUserDetails(String userName){
		String address = addressService.getAddressForUser(userName);
		return String.format("User %s, %s", userName, address);
	}
}

Of course this code doesn’t make much sense, but will be good to demonstrate how to mock Spring bean. AddressDao just returns string and thus simulates read from some data source. It is autowired into AddressService. This bean is autowired into UserService, which is used to construct string with user name and address.

Notice that we are using constructor injection as field injection is considered as bad practice. If you want to enforce constructor injection for your application, Oliver Gierke (Spring ecosystem developer and Spring Data lead) recently created very nice project Ninjector.

Configuration which scans all these beans is pretty standard Spring Boot main class:

@SpringBootApplication
public class SimpleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SimpleApplication.class, args);
    }
}

Mock Spring bean (without AOP)

Let’s test the AddressService class where we mock AddressDao. We can create this mock via Spring’ @Profiles and @Primary annotations this way:

@Profile("AddressService-test")
@Configuration
public class AddressDaoTestConfiguration {
	@Bean
	@Primary
	public AddressDao addressDao() {
		return Mockito.mock(AddressDao.class);
	}
}

This test configuration will be applied only when Spring profile AddressService-test is active. When it’s applied, it registers bean of type AddressDao, which is mock instance created by Mockito. @Primary annotation tells Spring to use this instance instead of real one when somebody autowire AddressDao bean.

Test class is using JUnit framework:

@ActiveProfiles("AddressService-test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SimpleApplication.class)
public class AddressServiceITest {
	@Autowired 
	private AddressService addressService;

	@Autowired
	private AddressDao addressDao;

	@Test
	public void testGetAddressForUser() {
		// GIVEN
		Mockito.when(addressDao.readAddress("john"))
			.thenReturn("5 Bright Corner");

		// WHEN 
		String actualAddress = addressService.getAddressForUser("john");
  
		// THEN   
		Assert.assertEquals("5 Bright Corner", actualAddress);
	}
}

We activate profile AddressService-test to enable AddressDao mocking. Annotation @RunWith is needed for Spring integration tests and @SpringApplicationConfiguration defines which Spring configuration will be used to construct context for testing. Before the test, we autowire instance of AddressService under test and AddressDao mock.

Subsequent testing method should be clear if you are using Mockito. In GIVEN phase, we record desired behavior into mock instance. In WHEN phase, we execute testing code and in THEN phase, we verify if testing code returned value we expect.

Spy on Spring Bean (without AOP)

For spying example, will be spying on AddressService instance:

@Profile("UserService-test")
@Configuration
public class AddressServiceTestConfiguration {
	@Bean
	@Primary
	public AddressService addressServiceSpy(AddressService addressService) {
		return Mockito.spy(addressService);
	}
}

This Spring configuration will be component scanned only if profile UserService-test will be active. It defines primary bean of type AddressService. @Primary tells Spring to use this instance in case two beans of this type are present in Spring context.  During construction of this bean we autowire existing instance of AddressService from Spring context and use Mockito’s spying feature. The bean we are registering is effectively delegating all the calls to original instance, but Mockito spying allows us to verify interactions on spied instance.

We will test behavior of UserService this way:

@ActiveProfiles("UserService-test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SimpleApplication.class)
public class UserServiceITest {
	@Autowired
	private UserService userService;

	@Autowired
	private AddressService addressService;
 
	@Test
	public void testGetUserDetails() {
		// GIVEN - Spring scanned by SimpleApplication class

		// WHEN
		String actualUserDetails = userService.getUserDetails("john");
 
		// THEN
		Assert.assertEquals("User john, 3 Dark Corner", actualUserDetails);
		Mockito.verify(addressService).getAddressForUser("john");
	}
}

For testing we activate UserService-test profile so our spying configuration will be applied. We autowire UserService which is under test and AddressService, which is being spied via Mockito.

We don’t need to prepare any behavior for testing in GIVEN phase. WHEN phase is obviously executing code under test. In THEN phase we verify if testing code returned value we expect and also if addressService call was executed with correct parameter.

Problems with Mockito and Spring AOP

Let say now we want to use Spring AOP module to handle some cross-cutting concerns. For example to log calls on our Spring beans this way:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
    
@Aspect
@Component
@Slf4j
@Profile("aop") //only for example purposes
public class AddressLogger {
    @Before("execution(* net.lkrnac.blog.testing.mockbeanv2.beans.*.*(..))")
    public void logAddressCall(JoinPoint jp){
        log.info("Executing method {}", jp.getSignature());
    }
}

This AOP Aspect is applied before call on Spring beans from package net.lkrnac.blog.testing.mockbeanv2. It is using Lombok’s annotation @Slf4j to log signature of called method. Notice that this bean is created only when aop profile is defined. We are using this profile to separate AOP and non-AOP testing examples. In a real application you wouldn’t want to use such profile.

We also need to enable AspectJ for our application, therefore all the following examples will be using this Spring Boot main class:

@SpringBootApplication
@EnableAspectJAutoProxy
public class AopApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopApplication.class, args);
    }
}

AOP constructs are enabled by @EnableAspectJAutoProxy.

But such AOP constructs may be problematic if we combine Mockito for mocking with Spring AOP. It is because both use CGLIB to proxy real instances and when Mockito proxy is wrapped into Spring proxy, we can experience type mismatch problems. These can be mitigated by configuring bean’s scope with ScopedProxyMode.TARGET_CLASS, but Mockito verify() calls still fail with NotAMockException. Such problems can be seen if we enable aop profile for UserServiceITest.

Mock Spring bean proxied by Spring AOP

To overcome these problems, we will wrap mock into this Spring bean:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;

import org.mockito.Mockito;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;

import lombok.Getter;
import net.lkrnac.blog.testing.mockbeanv2.beans.AddressDao;

@Primary
@Repository
@Profile("AddressService-aop-mock-test")
public class AddressDaoMock extends AddressDao{
    @Getter
    private AddressDao mockDelegate = Mockito.mock(AddressDao.class);
    
    public String readAddress(String userName) {
        return mockDelegate.readAddress(userName);
    }
}

@Primary annotation makes sure that this bean will take precedence before real AddressDao bean during injection. To make sure it will be applied only for specific test, we define profile AddressService-aop-mock-test for this bean. It inherits AddressDao class, so that it can act as full replacement of that type.

In order to fake behavior, we define mock instance of type AddressDao, which is exposed via getter defined by Lombok’s @Getter annotation. We also implement readAddress() method which is expected to be called during test. This method just delegates the call to mock instance.

The test where this mock is used can look like this:

@ActiveProfiles({"AddressService-aop-mock-test", "aop"})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AopApplication.class)
public class AddressServiceAopMockITest {
    @Autowired
    private AddressService addressService; 

    @Autowired
    private AddressDao addressDao;
    
    @Test
    public void testGetAddressForUser() {
        // GIVEN
        AddressDaoMock addressDaoMock = (AddressDaoMock) addressDao;
        Mockito.when(addressDaoMock.getMockDelegate().readAddress("john"))
            .thenReturn("5 Bright Corner");
 
        // WHEN 
        String actualAddress = addressService.getAddressForUser("john");
 
        // THEN  
        Assert.assertEquals("5 Bright Corner", actualAddress);
    }
}

In the test we define AddressService-aop-mock-test profile to activate AddressDaoMock and aop profile to activate AddressLogger AOP aspect. For testing, we autowire testing bean addressService and its faked dependency addressDao. As we know, addressDao will be of type AddressDaoMock, because this bean was marked as @Primary. Therefore we can cast it and record behavior into mockDelegate.

When we call testing method, recorded behavior should be used because we expect testing method to use AddressDao dependency.

Spy on Spring bean proxied by Spring AOP

Similar pattern can be used for spying the real implementation. This is how our spy can look like:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;

import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import lombok.Getter;
import net.lkrnac.blog.testing.mockbeanv2.beans.AddressDao;
import net.lkrnac.blog.testing.mockbeanv2.beans.AddressService;

@Primary
@Service
@Profile("UserService-aop-test")
public class AddressServiceSpy extends AddressService{
    @Getter
    private AddressService spyDelegate;
    
    @Autowired
    public AddressServiceSpy(AddressDao addressDao) {
        super(null);
        spyDelegate = Mockito.spy(new AddressService(addressDao));
    }
    
    public String getAddressForUser(String userName){
        return spyDelegate.getAddressForUser(userName);
    }
}

As we can see this spy is very similar to AddressDaoMock. But in this case real bean is using constructor injection to autowire its dependency. Therefore we’ll need to define non-default constructor and do constructor injection also. But we wouldn’t pass injected dependency into parent constructor.

To enable spying on real object, we construct new instance with all the dependencies, wrap it into Mockito spy instance and store it into spyDelegate property. We expect call of method getAddressForUser() during test, therefore we delegate this call to spyDelegate. This property can be accessed in test via getter defined by Lombok’s @Getter annotation.

Test itself would look like this:

@ActiveProfiles({"UserService-aop-test", "aop"})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AopApplication.class)
public class UserServiceAopITest {
    @Autowired
    private UserService userService;

    @Autowired
    private AddressService addressService;
    
    @Test
    public void testGetUserDetails() {
        // GIVEN
        AddressServiceSpy addressServiceSpy = (AddressServiceSpy) addressService;

        // WHEN
        String actualUserDetails = userService.getUserDetails("john");
  
        // THEN 
        Assert.assertEquals("User john, 3 Dark Corner", actualUserDetails);
        Mockito.verify(addressServiceSpy.getSpyDelegate()).getAddressForUser("john");
    }
}

It is very straight forward. Profile UserService-aop-test ensures that AddressServiceSpy will be scanned. Profile aop ensures same for AddressLogger aspect. When we autowire testing object UserService and its dependency AddressService, we know that we can cast it to AddressServiceSpy and verify the call on its spyDelegate property after calling the testing method.

Fake Spring bean proxied by Spring AOP

It is obvious that delegating calls into Mockito mocks or spies complicates the testing. These patterns are often overkill if we simply need to fake the logic. We can use such fake in that case:

@Primary
@Repository
@Profile("AddressService-aop-fake-test")
public class AddressDaoFake extends AddressDao{
    public String readAddress(String userName) {
        return userName + "'s address";
    }
}

and used it for testing this way:

@ActiveProfiles({"AddressService-aop-fake-test", "aop"})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AopApplication.class)
public class AddressServiceAopFakeITest {
    @Autowired
    private AddressService addressService; 

    @Test
    public void testGetAddressForUser() {
        // GIVEN - Spring context
 
        // WHEN 
        String actualAddress = addressService.getAddressForUser("john");
 
        // THEN  
        Assert.assertEquals("john's address", actualAddress);
    }
}

I don’t think this test needs explanation.

Source code for these examples is hosted on Github.

mock Spring bean, encapsulate spring bean

How to mock Spring bean without Springockito

NEW EDIT: As of Spring Boot 1.4.0, faking of Spring Beans is supported natively via annotation @MockBean. Read Spring Boot docs for more info.

OLD EDIT: Here is better example how to mock Spring bean.

I work with Spring several years. But I was always frustrated with how messy can XML configuration become. As various annotations and possibilities of Java configuration were popping up, I started to enjoy programming with Spring. That is why I strongly entourage using Java configuration. In my opinion, XML configuration is suitable only when you need to have visualized Spring Integration or Spring Batch flow. Hopefully Spring Tool Suite will be able to visualize Java configurations for these frameworks also.

One of the nasty aspects of XML configuration is that it often leads to huge XML configuration files. Developers therefore often create test context configuration for integration testing. But what is the purpose of integration testing, when there isn’t production wiring tested? Such integration test has very little value. So I was always trying to design my production contexts in testable fashion.

I except that when you are creating new project / module you would avoid XML configuration as much as possible.  So with Java configuration you can create Spring configuration per module / package and scan them in main context (@Configuration is also candidate for component scanning). This way you can naturally create islands Spring beans. These islands can be easily tested in isolation.

But I have to admit that it’s not always possible to test production Java configuration as is. Rarely you need to amend behavior or spy on certain beans. There is library for it called Springockito (EDIT: Springokito link dissapeared). To be honest I didn’t use it so far, because I always try to design Spring configuration to avoid need for mocking. Looking at Springockito pace of development (EDIT: Springokito link dissapeared) and number of open issues  (EDIT: Springokito link dissapeared), I would be little bit worried to introduce it into my test suite stack. Fact that last release was done before Spring 4 release brings up questions like “Is it possible to easily integrate it with Spring 4?”. I don’t know, because I didn’t try it. I prefer pure Spring approach if I need to mock Spring bean in integration test.

Spring provides @Primary  annotation for specifying which bean should be preferred in the case when two beans with same type are registered. This is handy because you can override production bean with fake bean in integration test. Let’s explore this approach and some pitfalls on examples.

I chose this simplistic / dummy production code structure for demonstration:

@Repository
public class AddressDao {
	public String readAddress(String userName) {
		return "3 Dark Corner";
	}
}

@Service
public class AddressService {
    private AddressDao addressDao;
    
    @Autowired
    public AddressService(AddressDao addressDao) {
        this.addressDao = addressDao;
    }
    
    public String getAddressForUser(String userName){
        return addressDao.readAddress(userName);
    }
}

@Service
public class UserService {
    private AddressService addressService;

    @Autowired
    public UserService(AddressService addressService) {
        this.addressService = addressService;
    }
    
    public String getUserDetails(String userName){
        String address = addressService.getAddressForUser(userName);
        return String.format("User %s, %s", userName, address);
    }
}

AddressDao singleton bean instance is injected into AddressService. AddressService is similarly used in UserService.

I have to warn you at this stage. My approach is slightly invasive to production code. To be able to fake existing production beans, we have to register fake beans in integration test. But these fake beans are usually in the same package sub-tree as production beans (assuming you are using standard Maven files structure: “src/main/java” and “src/test/java”). So when they are in the same package sub-tree, they would be scanned during integration tests. But we don’t want to use all bean fakes in all integration tests. Fakes could break unrelated integration tests. So we need to have mechanism, how to tell the test to use only certain fake beans. This is done by excluding fake beans from component scanning completely. Integration test explicitly define which fake/s are being used (will show this later). Now let’s take a look at mechanism of excluding fake beans from component scanning. We define our own marker annotation:

public @interface BeanMock {
}

And exclude @BeanMock annotation from  component scanning in main Spring configuration.

@Configuration
@ComponentScan(excludeFilters = @Filter(BeanMock.class))
@EnableAutoConfiguration
public class Application {
}

Root package of component scan is current package of Application class. So all above production beans needs to be in same package or sub-package. We are now need to create integration test for UserService. Let’s spy on address service bean. Of course such testing doesn’t  make practical sense with this production code, but this is just example. So here is our spying bean:

@Configuration
@BeanMock
public class AddressServiceSpy {
	@Bean
	@Primary
	public AddressService registerAddressServiceSpy(AddressService addressService) {
		return spy(addressService);
	}
}

Production AddressService bean is autowired from production context, wrapped into Mockito‘s spy and registered as primary bean for AddressService type. @Primary annotation makes sure that our fake bean will be used in integration test instead of production bean. @BeanMock annotation ensures that this bean can’t be scanned by Application component scanning. Let’s take a look at the integration test now:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class, AddressServiceSpy.class })
public class UserServiceITest {
    @Autowired
    private UserService userService;

    @Autowired
    private AddressService addressService;

    @Test
    public void testGetUserDetails() {
        // GIVEN - spring context defined by Application class

        // WHEN
        String actualUserDetails = userService.getUserDetails("john");

        // THEN
        Assert.assertEquals("User john, 3 Dark Corner", actualUserDetails);
        verify(addressService, times(1)).getAddressForUser("john");
    }
}

@SpringApplicationConfigration annotation has two parameters. First (Application.class) declares Spring configuration under test. Second parameter (AddressServiceSpy.class) specifies fake bean that will be loaded for our testing into Spring IoC container. It’s obvious that we can use as many bean fakes as needed, but you don’t want to have many bean fakes. This approach should be used rarely and if you observe yourself using such mocking often, you are probably having serious problem with tight coupling in your application or within your development team in general. TDD methodology should help you target this problem. Bear in mind: “Less mocking is always better!”. So consider production design changes that allow for lower usage of mocks. This applies also for unit testing.

Within integration test we can autowire  this spy bean and use it for various verifications. In this case we verified if testing method userService.getUserDetails called method addressService.getAddressForUser with parameter “john”.

I have one more example. In this case we wouldn’t spy on production bean. We will mock it:

@Configuration
@BeanMock
public class AddressDaoMock {
	@Bean
	@Primary
	public AddressDao registerAddressDaoMock() {
		return mock(AddressDao.class);
	}
}

Again we override production bean, but this time we replace it with Mockito’s mock. We can than record behavior for mock in our integration test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class, AddressDaoMock.class })
public class AddressServiceITest {
	@Autowired
	private AddressService addressService;

	@Autowired
	private AddressDao addressDao;

	@Test
	public void testGetAddressForUser() {
		// GIVEN
		when(addressDao.readAddress("john")).thenReturn("5 Bright Corner");

		// WHEN
		String actualAddress = addressService.getAddressForUser("john");

		// THEN
		Assert.assertEquals("5 Bright Corner", actualAddress);
	}

	@After
	public void resetMock() {
		reset(addressDao);
	}
}

We load mocked bean via @SpringApplicationConfiguration‘s parameter. In test method, we stub addressDao.readAddress method to return “5 Bright Corner” string when “john” is passed to it as parameter.

But bear in mind that recorded behavior can be carried to different integration test via Spring context. We don’t want tests affecting each other. So you can avoid future problems in your test suite by reseting mocks after test. This is done in method resetMock.

Source code is on Github.

Black Box Testing of Spring Boot Microservice is so easy

When I needed to do prototyping, proof of concept or play with some new technology in free time, starting new project was always a little annoying barrier with Maven. Have to say that setting up Maven project is not hard and you can use Maven Archetypes. But Archetypes are often out of date. Who wants to play with old technologies? So I always end up wiring in dependencies I wanted to play with. Not very productive spent time.

But than Spring Boot came to my way. I fell in love. In last few months I created at least 50 small playground projects, prototypes with Spring Boot. Also incorporated it at work. It’s just perfect for prototyping, learning, microservices, web, batch, enterprise, message flow or command line applications. You have to be dinosaur or be blind not to evaluate Spring Boot for your next Spring project. And when you finish evaluate it, you will go for it. I promise.

I feel a need to highlight how easy is Black Box Testing of Spring Boot microservice. Black Box Testing refers to testing without any poking with application artifact. Such testing can be called also integration testing. You can also perform performance or stress testing way I am going to demonstrate.

Spring Boot Microservice is usually web application with embedded Tomcat. So it is executed as JAR from command line. There is possibility to convert Spring Boot project into WAR artifact, that can be hosted on shared Servlet container. But we don’t want that now. It’s better when microservice has its own little embedded container.

I used existing Spring’s REST service guide as testing target. Focus is mostly on testing project, so it is handy to use this “Hello World” REST application as example. I expect these two common tools are set up and installed on your machine:

So we’ll need to download source code and install JAR artifact into our local repository. I am going to use command line to download and install the microservice. Let’s go to some directory where we download source code. Use these commands:

git clone git@github.com:spring-guides/gs-rest-service.git
cd gs-rest-service/complete
mvn clean install

If everything went OK, Spring Boot microservice JAR artifact is now installed in our local Maven repository. In serious Java development, it would be rather installed into shared repository (e.g. Artifactory, Nexus,… ). When our microservice is installed, we can focus on testing project. It is also Maven and Spring Boot based.

Black box testing will be achieved by downloading the artifact from Maven repository (doesn’t matter if it is local or remote). Maven-dependency-plugin can help us this way:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>compile</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <includeArtifactIds>gs-rest-service</includeArtifactIds>
                <stripVersion>true</stripVersion>
            </configuration>
        </execution>
    </executions>
</plugin>

It downloads microservice artifact into target/dependency directory by default. As you can see, it’s hooked to compile phase of Maven lifecycle, so that downloaded artifact is available during test phase. Artifact version is stripped from version information. We use latest version. It makes usage of JAR artifact easier during testing.

Readers skilled with Maven may notice missing plugin version. Spring Boot driven project is inherited from parent Maven project called spring-boot-starter-parent. It contains versions of main Maven plugins. This is one of the Spring Boot’s opinionated aspects. I like it, because it provides stable dependencies matrix. You can change the version if you need.

When we have artifact in our file system, we can start testing. We need to be able to execute JAR file from command line. I used standard Java ProcessBuilder this way:

public class ProcessExecutor {
	public Process execute(String jarName) throws IOException {
		Process p = null;
		ProcessBuilder pb = new ProcessBuilder("java", "-jar", jarName);
		pb.directory(new File("target/dependency"));
		File log = new File("log");
		pb.redirectErrorStream(true);
		pb.redirectOutput(Redirect.appendTo(log));
		p = pb.start();
		return p;
	}
}

This class executes given process JAR based on given file name. Location is hard-coded to  target/dependency directory, where maven-dependency-plugin located our artifact. Standard and error outputs are redirected to file. Next class needed for testing is DTO (Data  transfer object). It is simple POJO that will be used for deserialization from JSON. I use Lombok project to reduce boilerplate code needed for getters, setters, hashCode and equals.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Greeting {
    private long id;
    private String content;
}

Test itself looks like this:

public class BlackBoxTest {
	private static final String RESOURCE_URL = "https://localhost:8080/greeting";

	@Test
	public void contextLoads() throws InterruptedException, IOException {
		Process process = null;
		Greeting actualGreeting = null;
		try {
			process = new ProcessExecutor().execute("gs-rest-service.jar");

			RestTemplate restTemplate = new RestTemplate();
			waitForStart(restTemplate);

			actualGreeting = restTemplate.getForObject(RESOURCE_URL, Greeting.class);
		} finally {
			process.destroyForcibly();
		}
		Assert.assertEquals(new Greeting(2L, "Hello, World!"), actualGreeting);
	}

	private void waitForStart(RestTemplate restTemplate) {
		while (true) {
			try {
				Thread.sleep(500);
				restTemplate.getForObject(RESOURCE_URL, String.class);
				return;
			} catch (Throwable throwable) {
				// ignoring errors
			}
		}
	}
}

It executes Spring Boot microservice process first and wait unit it starts. To verify if microservice is started, it sends HTTP request to URL where it’s expected. The service is ready for testing after first successful response. Microservice should send simple greeting JSON response for HTTP GET request. Deserialization from JSON into our Greeting DTO is verified at the end of the test.

Source code is shared on Github.

Mastering Unit Testing Using Mockito and JUnit

Book Review: Mastering Unit Testing Using Mockito and JUnit

I was asked by Packt Publishing to write a review blog post about the new book Mastering Unit Testing Using Mockito and JUnit by Sujoy Acharya (released in Jun 2014). As I am passionate about all topics around testing or continuous development, I got exited. Nice side effect of this is that I could read this book for free ;). Book is 314 pages long. Divided into 10 chapters.

Preface

Summarizes why reader wants to test. Also why wants to have automated feedback loop. But there was very strong statement: “Greenfield projects always follow test-driven development to deliver maintainable and testable code.” Of course author probably wrote this before test first / test last battle. I am personally also TDD infected but there are definitely situations where it doesn’t make sense to do test first or test at all (e.g. prototyping). Also we should accept existence of test last approach. There are certainly very strong TDD opponents:

Chapter 1: JUnit4 – A Total recall

Guides reader how to create simple project in Eclipse. Leads him through JUnit features. It starts with basic fundamentals. Later in the chapter are described advanced parts of JUnit API. Some of these parts of the API should be used rarely or not at all (e.g. test methods ordering). This would be worth mentioning for beginners.  I wasn’t very excited because I am TestNG user. If you ever wrote some unit tests you probably would want to skip this chapter. Surprising for me was comparison of JUnit 4 @Before annotation with JUnit 3 setUp(). JUnit 4 is already 8 years old.

Chapter 2: Automating JUnit Tests

Elaborates about Continuous Integration. Also provides basic information about Gradle, Maven and Ant. Demonstrates very simple configurations of each build tool and how they run tests. Lastly touches simple Jenkins integration with each mentioned tool. Shame that configuration of examples across the book weren’t driven by any of this build tools.

Chapter 3:  Test Doubles

Brief explanation of theory behind faking dependencies of testing object. It also contains examples of each type (without usage of any testing framework so far).

Chapter 4: Progressive Mockito

Demonstrates Mockito syntax on examples. It goes through basic and also advanced Mockito features. At the end of the chapter is mentioned BDD (Behavioral driven development) style of testing. The only disturbing moment was manual inclusion of dependencies in example project configuration. Build tools were discussed in Chaper 2.

Chapter 5: Exploring Code Coverage

Author explains what code coverage means. After that shows some ways how to measure code coverage from Eclipse. I was surprised that he still accepts Cobertura as relevant tool, because Cobertura is dead project now. Last version was working only for Java 6. Java 6 was marked as “End of life” more that a year ago. That is why integration examples of Cobertura with Ant and Maven aren’t very useful. Examples how to integrate them with JaCoCo would be much more appropriate. I integrated JaCoCo with Maven in the past. It’s definitely doable.

EDIT: Cobertura is again under active development and is working for Java 7 now.

Chapter 6: Revealing Code Quality

This chapter shows three very useful Java static code analyzers

  • PMD
  • FindBugs
  • CheckStyle

Than it introduces SonarQube and its integration with mentioned build tools. It is very handy tool for monitoring technical depth on the project.

Chapter 7: Unit Testing the Web Tier

Some examples how you can test

  • Servlets
  • Spring MVC

But Spring MVC examples with Spring Test’s MockMvc library are missing. Examples in this chapter contain only plain Mockito + JUnit libraries. Readers should definitely take a look at MockMvc capabilities, because they are much more handier than explained approach.

Chapter 8: Playing with Data

This time author focuses on DAO layer. My personal opinion is that mocking Connetion or PreparedStatement in tests isn’t quite right. You can have test passing, but when you execute SQL statement against DB it can fail on some SQL error. I prefer to have integration tests for DAO layer.

Chapter 9: Solving Test Puzzles

Discusses constructs known as testability killers and some approaches how to solve them. I also discussed this topic in blog post series. I am glad that author doesn’t suggest usage of PowerMock. Rather takes the path of changing production code to enhance testability. Totally agree. Finally it shows example of TDD style of programming. Shame that this is the only example in the book where test is introduced before production code. So all other examples doesn’t follow TDD.

Chapter 10: Best Practices

This chapter dives into some common pitfalls reader can fall during writing the tests. Such advices are always good to keep in mind.

Conclusion

“Mastering Unit Testing Using Mockito and JUnit” book declares that was written for advanced to novice software testers and developers who use Mockito and JUnit framework. I would say that is only for beginners. It is mainly because book is covering wide range of topics around testing and its automation. There isn’t enough place dive deeply. Positive is covering nearly all aspects of professional unit testing. So it is very good start for developers that are willing to explore benefits of automated feedback loop. Author takes approach of hands on examples, so it is much better to read it next to the computer.

Why is wide usage of PowerMock problematic

There are Java constructs well known for their testability issues:

  • Private methods
  • Static methods
  • Constuctors
  • Final methods or classes

Skilled Java developer following TDD tries to minimize their testability impacts. Don’t want to dive into techniques to enhance testability. They are explained well on Misko Hevery’s blog.

Some developers argue that we have frameworks today (like PowerMock or JMockIt) that are able mock these testability killers. And it’s true. So should we throw factory methods to bin and start using static or singleton classes widely? The answer is NO. Reason is in Java language nature. There isn’t way how to mock mentioned constructs using Java features like inheritance, polymorphism or reflection. Byte-code manipulation is needed. And that is the problem.

Here are some facts about PowerMock:

  • It is using Javassist library for byte-code manipulation
  • It took 1.5 years to make PowerMock + Javaassist compatible with Java7 since its introduction. Here is note from PowerMock change log:
Change log 1.5 (2012-12-04)
---------------------------
Upgraded to Javassist 3.17.1-GA, this means that PowerMock works in Java 7!

I tried to use PowerMock and JMockIt to test some legacy code. The result weren’t acceptable for me. Sometimes there were some strange crashes or clash with JaCoCo test coverage tool (have to say that I didn’t give JMockIt deep chance and abandoned on it immediately after first problems). At the end I always decided to change the production code to enhance testability and use plain Mockito.

If it would be up to me I would exclude byte-code manipulation testing frameworks from technology stack completely. Java8 is coming soon and potential migration of unit tests can be a big problem if it is used widely. It would be ridiculous to wait 1.5 years for Java8 update because of testing framework.

I respect PowerMock and JMockIt projects and people behind them. They are sometimes valuable in cases when you have to deal with legacy code or third party libraries.