The magic of Interfaces: use JMS to create Queue/Topic producers and consumers

Remove particular implementations and use interfaces (for JMS or other features) improve the independency and flexibility of your application: with a few changes you can change providers, APIs or products without modify your business/main logic

Advertisements

A few week ago I had a requirement to create a message producer for a TIBCO-EMS Topic. It was a very simple task.
The problem started when I needed to test if the sent messages were on the Topic… and I didn’t have access to the Topic’s Admin console.
So I started to research how to create a message producer but also a message consumer. I founded a lot of examples on Internet but most of them depended of the queue/topic implementation and they didn’t use JMS interfaces.
Finally, I created a producer/consumer JAVA program for the TIBCO-EMS implementation. My co-workers found it very useful to test the sent and received messages and asked to me if I could “configure” for IBM-MQ queues.
The original program became in a Spring Boot Application that removes the particular implementations and uses JMS interfaces for several operations. The next step was transform the local project in a Web Application with a very simple (and ugly) interface to test the send, browse/consume and remove operations on different configured topics and queues: the JmsToolkitWeb.
If you found a better solution for one or more feature or you want to share your best practices with us, please, let me know and I will update this post 🙂

Some tips

  • The application uses JAVA JMS interfaces so you don’t depend of the implementation of the queue/topic provider
  • You only need to create a JMS ConnectionFactory Bean using the Connection Factory provided by you selected queue/topic driver
  • You don’t need access to Administrator console to perform operation with the messages
  • Includes Restful End-points for different queue/topic operations
  • Creates initial topic subscribers for the configured topics when the Application starts (you don’t need to create through the Administrator console)
  • Developed with Spring Boot Application 1.5.3.RELEASE version (and also tested with 1.4.2.RELEASE version)
  • Configured by default to use Apache Active-MQ
  • Tested with TIBCO-EMS, IBM-MQ and Apache ActiveMQ providers

Configuration

  • TIBCO-EMS
    • add the Maven dependency to pom.xml
    • create a Bean for the JMS ConnectionFactoring using new com.tibco.tibjms.TibjmsConnectionFactory(url)
    • set the specific values using a JmsTemplate and set the ConnectionFactory to this JmsTemplate
    • instantiate the JmsTemplate to get the ConnectionFactory in your services (for example, use @Autowired annotation)
  • IBM-MQ
    • add the Maven dependency to pom.xml
    • create a Bean for the JMS ConnectionFactoring using new com.ibm.mq.jms.MQConnectionFactory();
    • set the specific values for the MQ Connection Factory
    • instantiate the ConnectionFactory in your services (for example, use @Autowired annotation)
  • Apache Active-MQ
    • add the Maven dependency to pom.xml
    • create a Bean for the JMS ConnectionFactoring using new ActiveMQConnectionFactory();
    • set the specific values for the MQ Connection Factory
    • instantiate the ConnectionFactory in your services (for example, use @Autowired annotation)

Example for ActiveMQ

Add the Maven dependencies

Add the Spring Boot starter test dependency to your pom.xml

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-activemq</artifactId>
		</dependency>

Create a JMS ConnectionFactory Bean

Here you create your Queue/Topic connection using your provider method(s). In the other classes you only use JMS interfaces so if in the future you need to change your provider you only will modify this bean 🙂

package com.example.jms.config;

import javax.jms.ConnectionFactory;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
 * Configuration class for JMS beans.
 * @author Gabriel
 *
 */
@Configuration
@ConfigurationProperties("com.exmaple.jms.config.activemq")
@Profile("default")
public class JmsLocalConfig {

	private String url;
	private String user;
	private String password;
	
	/**
	 * Creates a {@link ConnectionFactory} for your configured JMS provider.
	 * @return
	 */
	@Bean
	public ConnectionFactory createConnectionFactoryBean() {
		ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
		connectionFactory.setBrokerURL(url);
		connectionFactory.setUserName(ActiveMQConnection.DEFAULT_USER); // or connectionFactory.setUserName(user);
		connectionFactory.setPassword(ActiveMQConnection.DEFAULT_PASSWORD); // or connectionFactory.setPassword(password);
		return connectionFactory;
	}
	
	// methods for getters and setters
}	

Create a JMS Queue producer

package com.example.jms.service.queue;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;

import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Services for JMS queues.
 * @author Gabriel
 *
 */
@Service
public class QueueService {

	private static final Logger LOGGER = LoggerFactory.getLogger(QueueService.class);
	
	private static final int RECEIVE_TIME_OUT_MILISECONDS = 5000;
	
	@Autowired
	ConnectionFactory connectionFactory;

	/**
	 * Sends the given message to the given queue code.
	 * @param queueDestinationName
	 * @param message
	 * @return
	 */
	public boolean sendMessageTo(final String queueDestinationName, final String message) {
		LOGGER.info("sendMessageTo - start");
		
		Connection connection = null;
		Session session = null;

		try {
			connection = connectionFactory.createConnection();
			connection.setClientID("SendQueueSample");

			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			Destination destination = session.createQueue(queueDestinationName);

			session.createProducer(destination).send(session.createTextMessage(message));
			return true;
		} catch (Exception e) {
			LOGGER.error("ERROR : ", e);
			return false;
		} finally {
			closeSession(session);
			closeConnection(connection);
			LOGGER.info("sendMessageTo - end");
		}
	}
}

Create a JMS Topic producer

package com.example.jms.service.topic;

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

import javax.annotation.PostConstruct;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;

import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.jms.enums.ResourcesEnum;

/**
 * Services for topics.
 * @author Gabriel
 *
 */
@Service
public class TopicService {

	private static final Logger LOGGER = LoggerFactory.getLogger(TopicService.class);
	
	private static final String SUBSCRIBER_NAME = "theSubscriber";
	private static final int RECEIVE_TIME_OUT_MILISECONDS = 5000;
	
	private Map<String,String> subscribers = new HashMap<>();
	
	@Autowired
	ConnectionFactory connectionFactory;
	
	/**
	 * Sends the given message to the given topic resource. 
	 * @param topicDestinationName
	 * @param message
	 * @return
	 */
	public boolean sendMessageTo(final String topicDestinationName, final String message) {
        LOGGER.info("sendMessageTo - start");
        
        Connection connection = null;
        Session session = null;
    
        try {
            connection = connectionFactory.createConnection();
            connection.setClientID(topicDestinationName);
            
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            Destination destination = session.createTopic(topicDestinationName);            
            
            session.createProducer(destination).send(session.createTextMessage(message));
            
            LOGGER.debug("sendMessageTo - message sent ok to : {}", topicDestinationName);
            LOGGER.debug("sendMessageTo - message sent as    : {}", SUBSCRIBER_NAME);
            LOGGER.debug("sendMessageTo - message body       : {}", message);
            
            return true;
        } catch (Exception e) {
        	LOGGER.error("ERROR", e);
            return false;
        } finally {
            closeSesion(session);
            closeConnection(connection);                        
            LOGGER.info("sendMessageTo - end");
        }
	}
}

Create a JMS Queue consumer

	/**
	 * Removes/Consumes the messages from a given queue resource.
     * Only for test purpose: this feature will be executed through the queue's administrator console.
	 * @param queueDestinationName
	 * @return
	 */
	public boolean removeMessagesFrom(final String queueDestinationName) {
		LOGGER.info("removeMessagesFrom - start");
		
		Connection connection = null;
		Session session = null;
		MessageConsumer messageConsumer = null; 
				
		try {
			connection = connectionFactory.createConnection();
			connection.setClientID("ConsumeQueueSample");
			connection.start();
			
			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			Destination destination = session.createQueue(queueDestinationName);

			messageConsumer = session.createConsumer(destination);
			Message receivedMessage = messageConsumer.receive(RECEIVE_TIME_OUT_MILISECONDS);

			while (receivedMessage != null) {
				receivedMessage = messageConsumer.receive(RECEIVE_TIME_OUT_MILISECONDS);
			}

			return true;
		} catch (Exception e) {
			LOGGER.error("EROR : ", e);
			return false;
		} finally {
			closeMessageConsumer(messageConsumer);
			closeSession(session);
			closeConnection(connection);
			LOGGER.info("removeMessagesFrom - end");
		}
	}

Create a JMS Topic subscriber

    /**
     * Removes/Consumes the messages from a given topic resource.
     * Only for test purpose: this feature will be executed through the topic's administrator console.
     * @param topicDestinationName
     * @return
     */
	public boolean removeMessagesBySubscriberFrom(final String topicDestinationName) {
		LOGGER.info("removeMessagesBySubscriberFrom - start");
		
        Connection connection = null;
        Session session = null;
        
        try {
            connection = connectionFactory.createConnection();
            connection.setClientID(topicDestinationName);
            connection.start();
            
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Topic destination = session.createTopic(topicDestinationName);            

            for (String subscriber : subscribers.keySet()) {
            	if (subscribers.get(subscriber).equals(topicDestinationName)) {
                	LOGGER.debug("removeMessagesBySubscriberFrom - topic : {} - subscriber : {}", topicDestinationName, subscriber);
                	
		        	MessageConsumer messageConsumer = session.createDurableSubscriber(destination, subscriber);
		        	Message receivedMessage = messageConsumer.receive(RECEIVE_TIME_OUT_MILISECONDS);
		            
		            while(receivedMessage != null) {
		            	receivedMessage = messageConsumer.receive(RECEIVE_TIME_OUT_MILISECONDS);
		            }
		            
		            closeMessageConsumer(messageConsumer);
            	}
            }
            return true;
        } catch (Exception e) {
        	LOGGER.error("ERROR", e);
            return false;
        } finally {
            closeSesion(session);
            closeConnection(connection);  
            LOGGER.info("removeMessagesBySubscriberFrom - end");
        }
	}

Create a JMS Queue browser

	/**
	 * Browses and gets the messages from the given queue resource.
	 * @param queueDestinationName
	 * @return
	 */
	public Map<String, String> browseMessagesFrom(final String queueDestinationName) {
		LOGGER.info("browseMessagesFrom - start");
		
		Map<String, String> queueMessages = new HashMap<>();
		Connection connection = null;
		Session session = null;
		
		try {
			connection = connectionFactory.createConnection();
			connection.setClientID("BrowseQueueSample");
			connection.start();
			
			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			Queue destination = session.createQueue(queueDestinationName);

			int elements = 1;

			@SuppressWarnings("unchecked")
			Enumeration<Message> messages = session.createBrowser(destination).getEnumeration();

			while (messages != null && messages.hasMoreElements()) {
				Message message = messages.nextElement();
				String textMessage = ((TextMessage) message).getText();
				queueMessages.put(String.valueOf(elements++), textMessage);
				
				LOGGER.debug("browseMessagesFrom - message : {}", textMessage);
			}
			
			return queueMessages;
		} catch (Exception e) {
			LOGGER.error("ERROR : ", e);
			return queueMessages;
		} finally {
			closeSession(session);
			closeConnection(connection);
			LOGGER.info("browseMessagesFrom - end");
		}
	}

Final notes
Remove particular implementations and use interfaces (for JMS or other features) improve the independency and flexibility of your application: with a few changes you can modify providers, APIs or products without change your busines/main logic.

You can get the complete code from my public GitHub repository:
https://github.com/Gabotto/JmsToolkitWebApplication

Let me know if you have any problem, comment or new ideas:
WordPress: https://gabelopment.wordpress.com/
Email: gabelopment@gmail.com

Also you can find me at Upwork

See you soon with more development notes…

JAVA Unit Test for Spring Boot with Mockito and EasyMock

Here they are some ideas about testing using the different tools given by Spring Boot Test dependency. For me and my team they are so useful when we write and run the Unit Test for medium or high complexity classes.

Here they are some ideas about testing using the different tools given by Spring Boot Test dependency. Maybe some tips are not consider as the best practices by the Spring Boot, Mockito, EasyMock and/or TDD folllowers but for me and my team they are so useful when we write and run the Unit Test for medium or high complexity classes.
If you found a better solution for one or more cases or you want to share your best practices with us, please, let me know and I will update this post :).

Add the Maven dependencies

Add the Spring Boot starter test dependency to your pom.xml

		<!--  junit test with mockito -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

If you prefer to use EasyMock as the Unit Test framework, add the this dependency to your pom.xml

		<!-- junit test with easymock -->
		<dependency>
		    <groupId>org.easymock</groupId>
		    <artifactId>easymock</artifactId>
		    <version>3.4</version>
			<scope>test</scope>
		</dependency>

If you need to mock some environment variables or system properties in your Unit Test cases you can use the “system-rules” dependency:

		<!-- mocking environment variables -->
		<dependency>
			<groupId>com.github.stefanbirkner</groupId>
			<artifactId>system-rules</artifactId>
			<version>1.16.0</version>
			<scope>test</scope>
		</dependency>

Some Notes for Spring Boot
Spring Boot provides a number of utilities and annotations to help you when you are testing your application.
Test support is provided by two modules: spring-boot-test contains core items and spring-boot-test-autoconfigure supports auto-configuration for tests.
The ‘Starter’ dependency imports both Spring Boot test modules as well has JUnit, AssertJ, Hamcrest and a number of other useful libraries:

  • JUnit: The standard for unit testing Java applications
  • Spring Test & Spring Boot Test: Utilities and integration test support for Spring Boot applications
  • AssertJ: A fluent assertion library
  • Hamcrest: A library of matcher objects (also known as constraints or predicates)
  • Mockito: A Java mocking framework
  • JSONassert: An assertion library for JSON
  • JsonPath: XPath for JSON

Tips for Spring Boot 1.4.1.RELEASE or higher

  • @RunWith(SpringRunner.class): Use this annotation to invoke the Spring’s runner version 1.4 in Spring Boot Test and common JUnit tests
  • @SpringBootTest: Annotation that creates the Spring Application Context and runs the servlet container. Useful for integration test but too complex for simple JUnit test cases
  • @MockBean: Creates an instance of Bean mocking all their methods. You can define/change behaviors using Mockito’s clauses
  • @SpyBean: Creates an instance of Bean that invokes to their real methods, except you define particular behaviors using Mockito’s clauses

Tips for Spring Boot 1.3.8.RELEASE or lower

  • As Spring Boot uses a previous version of Mockito framewrok, you don’t have the @RunWith, @SpringBootTest, @MockBean and @SpyBean annotations

General tips for Mockito, JUnit and Hamcrest

  • Mock: Creates an instance of the class mocking all their methods. You can define/change behaviors using Mockito’s clauses (for example doXXX, when or given)
  • Spy: Creates an instance of the class that invokes to their real methods, except you define particular behaviors using Mockito’s clauses (for example doXXX, when or given)
  • WhiteBox: Part of Mockito. Useful to set values to private fields by reflection (probably is not a good TDD practice)
  • doReturn/when clause: Set expected return value for a mock instance when invoke a method. In some cases works instead of when or give clauses
  • doThrow/when clause: Set expected thrown exception for a mock instance when invoke a method
  • doNothing/when clause: Set expected no action for a mock instance when invoke a method. Useful for mock void methods
  • doXXX: You can chain expected results for more than one interaction: doReturn(first interction expected result).doReturn(second interaction expected result).when…
  • AnyXXX: Applies the behavior to any parameter do you use in the mock object
  • Verify: Used to verify the invocation of the mock, the number of interactions (or no interactions) with the mock (or a specific method), the order of interactions, if an interaction has occurred at least certain number of times, the arguments of the interaction, etc
  • @InjectMocks: Inject mocks only either by constructor injection, setter injection, or property injection in order. Useful for Spring Boot versions lower than 1.4
  • Use @Rule and ExpectedException to test the expected exceptions. Important: you have to define as public field in your test class
  • The Hamcrest matchers assertThat, equalTo, notNullValue are easy to use and very descriptive
  • Use @Before annotation for your setUp method (will be executed before each test method execution in your class)
  • Use @After annotation for your tearDown method (will be executed after each test method execution in your class)
  • If you need to mock system properties, system environment variables or other java.lang system features, you could use system-rules dependency

Example – Test a Spring Boot Controller

Controller Class

package com.example.sample.unit.test.SampleUnitTestsSB_141.controller;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.sample.unit.test.SampleUnitTestsSB_141.service.ExampleService;

/**
 * Handles the request for the example. 
 * @author Gabriel
 *
 */
@RestController
public class ExampleController {

	private static final Logger LOGGER = LoggerFactory.getLogger(ExampleController.class);
	
	@Autowired
	ExampleService exampleService;
	
	/**
	 * Gets all configured names.
	 * @return
	 */
	@RequestMapping(path="/test/get", produces= MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<Map<String,String>> getAllNames() {
		LOGGER.info("getAllNames - start");
		ResponseEntity<Map<String,String>> responseEntity = null;
		
		try{
			Map<String,String> allNames = exampleService.getAllNames();
			responseEntity = new ResponseEntity<Map<String,String>>(allNames, HttpStatus.OK);
		} catch (Exception e) {
			Map<String,String> error = new HashMap<>();
			error.put("ERROR", e.getMessage());
			responseEntity = new ResponseEntity<Map<String,String>>(error, HttpStatus.BAD_REQUEST);
		}
		
		LOGGER.info("getAllNames - end");
		return responseEntity;		
	}	

}

Unit Test for the Controller Class using Mockito (with Spring Boot 1.4.1.RELEASE or higher)

package com.example.sample.unit.test.SampleUnitTestsSB_141.controller.mockito;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.sample.unit.test.SampleUnitTestsSB_141.controller.ExampleController;
import com.example.sample.unit.test.SampleUnitTestsSB_141.service.ExampleService;

import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.equalTo;

@RunWith(SpringRunner.class) // since 1.4.X version we can use this annotation to run the test using SB features
public class ExampleControllerTest {

	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// SpyBean instantiates the subject of test, injects the mocked dependencies and invokes the real object methods
	@SpyBean
	private ExampleController exampleController;
	
	// mock the autowired dependency of the test subject		
	@MockBean
	ExampleService exampleServiceMock;
	
	// expect values to be returned by the controller
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
		
		// we don't need initializes the mocked objects and their dependencies -> Spring Boot doing that 🙂 
		// MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithMapOfNamesAndHttpStatusOK() throws Exception {
		// you can use in static way or do a static import
		Mockito.doReturn(expectedNames).when(exampleServiceMock).getAllNames();
		
		// invokes the test subject that uses the mocked behaviors		
		ResponseEntity<Map<String,String>> result = exampleController.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(expectedNames.size()));
		assertThat(result.getBody().get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.getBody().get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.getBody().get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.getBody().get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.getBody().get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.getBody().get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(exampleServiceMock).getAllNames();
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithErrorAndHttpStatusBadRequestWhenExampleServiceFails() throws Exception {
		SQLException expectedException = new SQLException("Some Expected Exception");
		
		// forces to throw an exception from the service to test the controller's catch code
		Mockito.doThrow(expectedException).when(exampleServiceMock).getAllNames();
		
		// invokes the test subject that uses the mocked behaviors		
		ResponseEntity<Map<String,String>> result = exampleController.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.BAD_REQUEST));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(1));
		// should be the message of the service exception
		assertThat(result.getBody().get("ERROR"), equalTo(expectedException.getMessage()));

		Mockito.verify(exampleServiceMock).getAllNames();		
	}
}

Unit Test for the Controller Class using Spring Boot MVC Test feature (with Spring Boot 1.4.1.RELEASE or higher)

package com.example.sample.unit.test.SampleUnitTestsSB_141.controller.mvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import com.example.sample.unit.test.SampleUnitTestsSB_141.controller.ExampleController;
import com.example.sample.unit.test.SampleUnitTestsSB_141.service.ExampleService;

import net.minidev.json.JSONObject;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

@RunWith(SpringRunner.class) // since 1.4.X version we can use this annotation to run the test using SB features
@WebMvcTest(ExampleController.class) // performs a mvc unit test using the SB context (you can configure one for test purpose)
public class ExampleControllerTest {

	// Spring Boot class to perform restful operations
	@Autowired
	private MockMvc mockMVC;
	 
	// mock the autowired dependency of the test subject		
	@MockBean
	ExampleService exampleServiceMock;

	// expect values to be returned by the controller
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithMapOfNamesAndHttpStatusOK() throws Exception {
		// you can use in static way or do a static import
		// mocks the DAO behavior to return the expected names list
		Mockito.doReturn(expectedNames).when(exampleServiceMock).getAllNames();

		this.mockMVC.perform(get("/test/get"))
				.andExpect(status().isOk())
	            .andExpect(content().string(new JSONObject(expectedNames).toJSONString()));

		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(exampleServiceMock).getAllNames();
	}

	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithErrorAndHttpStatusBadRequestWhenExampleServiceFails() throws Exception {		
		// forces to throw an exception from the service to test the controller's catch block
		SQLException expectedException = new SQLException("Some Expected Exception");
		Mockito.doThrow(expectedException).when(exampleServiceMock).getAllNames();

		this.mockMVC.perform(get("/test/get"))
				.andExpect(status().isBadRequest())
	            .andExpect(content().string("{\"ERROR\":\"" +expectedException.getMessage()+ "\"}"));

		Mockito.verify(exampleServiceMock).getAllNames();		
	}
}

Unit Test for the Controller Class using Mockito (with Spring Boot 1.3.8.RELEASE or lower)

package com.example.sample.unit.test.SampleUnitTestsSB_138.controller.mockito;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.example.sample.unit.test.SampleUnitTestsSB_138.controller.ExampleController;
import com.example.sample.unit.test.SampleUnitTestsSB_138.service.ExampleService;

import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.equalTo;

// we don't have the @RunWith(SpringRunner.class) annotation -> we use the pure Mockito annotations
public class ExampleControllerTest {

	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// instantiates the subject of test and injects the mocked dependencies
	@InjectMocks // use to inject mocked objects in spring boot versions lower than 1.4
	private ExampleController exampleController;
	
	// mock the autowired dependency of the test subject	
	// we don't have the @MockBean in spring boot versions lower than 1.4 -> we use @Mock
	@Mock
	ExampleService exampleServiceMock;
	
	// expect values to be returned by the controller
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
		
		// initializes the mocked objects and injects the mocks to the object with @InjectMocks 
		MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithMapOfNamesAndHttpStatusOK() throws Exception {
		// you can use in static way or do a static import
		Mockito.doReturn(expectedNames).when(exampleServiceMock).getAllNames();
		
		// invokes the test subject that uses the mocked behaviors		
		ResponseEntity<Map<String,String>> result = exampleController.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(expectedNames.size()));
		assertThat(result.getBody().get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.getBody().get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.getBody().get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.getBody().get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.getBody().get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.getBody().get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(exampleServiceMock).getAllNames();
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithErrorAndHttpStatusBadRequestWhenExampleServiceFails() throws Exception {
		SQLException expectedException = new SQLException("Some Expected Exception");
		
		// forces to throw an exception from the service to test the controller's catch code
		Mockito.doThrow(expectedException).when(exampleServiceMock).getAllNames();
		
		// invokes the test subject that uses the mocked behaviors		
		ResponseEntity<Map<String,String>> result = exampleController.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.BAD_REQUEST));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(1));
		// should be the message of the service exception
		assertThat(result.getBody().get("ERROR"), equalTo(expectedException.getMessage()));

		Mockito.verify(exampleServiceMock).getAllNames();		
	}
}

Unit Test for the Controller Class using EasyMock

package com.example.sample.unit.test.SampleUnitTestsSB_141.controller.easymock;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.example.sample.unit.test.SampleUnitTestsSB_141.controller.ExampleController;
import com.example.sample.unit.test.SampleUnitTestsSB_141.service.ExampleService;

@RunWith(EasyMockRunner.class)
public class ExampleControllerTest {

	// instantiates the subject of test and injects the mocked dependencies
	@TestSubject
	ExampleController exampleController = new ExampleController();
	
	// mock the autowired dependency of the test subject
	@Mock
	ExampleService exampleServiceMock;
	
	// expect values to be returned by the controller
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithMapOfNamesAndHttpStatusOK() throws Exception {
		// you can use in static way or do a static import
		// mocks the expected behavior for the service in this test case
		// important: you will test only the logic and the coverage of the test subject so mock the dependecies for that
		EasyMock.expect(exampleServiceMock.getAllNames()).andReturn(expectedNames);
		// indicates to EasyMock that has to "record" the expected behavior of mock objects
		EasyMock.replay(exampleServiceMock);
		
		// invokes the test subject that uses the mocked behaviors		
		ResponseEntity<Map<String,String>> result = exampleController.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(expectedNames.size()));
		assertThat(result.getBody().get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.getBody().get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.getBody().get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.getBody().get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.getBody().get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.getBody().get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to EasyMock that verifies if the mocked objects were called
		EasyMock.verify(exampleServiceMock);
	}

	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAResponseEntityWithErrorAndHttpStatusBadRequestWhenExampleServiceFails() throws Exception {
		SQLException expectedException = new SQLException("Some Expected Exception");
		
		// forces to throw an exception from the service to test the controller's catch code
		EasyMock.expect(exampleServiceMock.getAllNames()).andThrow(expectedException);
		EasyMock.replay(exampleServiceMock);
		
		// invokes the test subject that uses the mocked behaviors		
		ResponseEntity<Map<String,String>> result = exampleController.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.BAD_REQUEST));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(1));
		// should be the message of the service exception
		assertThat(result.getBody().get("ERROR"), equalTo(expectedException.getMessage()));

		EasyMock.verify(exampleServiceMock);
	}	
}

Example – Test a Spring Boot Service

Service Class

package com.example.sample.unit.test.SampleUnitTestsSB_141.service;

import java.sql.SQLException;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.sample.unit.test.SampleUnitTestsSB_141.dao.ExampleDAO;

/**
 * Services for the example.
 * @author Gabriel
 *
 */
@Service
public class ExampleService {
	
	@Autowired
	ExampleDAO exampleDAO;
	
	/**
	 * Gets all configured names.
	 * @return
	 * @throws SQLException
	 */
	public Map<String,String> getAllNames() throws SQLException {
		return exampleDAO.findAll();
	}
}

Unit Test for the Service Class using Mockito (with Spring Boot 1.4.1.RELEASE or higher)

package com.example.sample.unit.test.SampleUnitTestsSB_141.service.mockito;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.sample.unit.test.SampleUnitTestsSB_141.dao.ExampleDAO;
import com.example.sample.unit.test.SampleUnitTestsSB_141.service.ExampleService;

import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.equalTo;

@RunWith(SpringRunner.class) // since 1.4.X version we can use this annotation to run the test using SB features
public class ExampleServiceTest {

	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// SpyBean instantiates the subject of test, injects the mocked dependencies and invokes the real object methods
	@SpyBean
	private ExampleService exampleService;
	
	// mock the autowired dependency of the test subject		
	@MockBean
	ExampleDAO exampleDAOMock;
	
	// expect values to be returned by the service
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
		
		// we don't need initializes the mocked objects and their dependencies -> Spring Boot doing that 🙂 
		// MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAMapWithAllNames() throws Exception {
		// you can use in static way or do a static import
		Mockito.doReturn(expectedNames).when(exampleDAOMock).findAll();
		
		// invokes the test subject that uses the mocked behaviors		
		Map<String,String> result = exampleService.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(expectedNames.size()));
		assertThat(result.get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(exampleDAOMock).findAll();
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldThrowASQLExceptionWhenDAOThrowsAnSQLException() throws Exception {
		SQLException expectedException = new SQLException("Some Expected DAO Exception");
		
		// should be before the test subject method invocation
		// indicates that the test case expects an exception of SQLException class with this message
		thrown.expect(SQLException.class);
		thrown.expectMessage(expectedException.getMessage());
								
		// forces to throw an exception from the service to test the controller's catch code
		Mockito.doThrow(expectedException).when(exampleDAOMock).findAll();
		
		// invokes the test subject that uses the mocked behaviors		
		// don't expect any assert because the service method should thrown an Exception
		exampleService.getAllNames();
				
		Mockito.verify(exampleDAOMock).findAll();		
	}
}

Unit Test for the Service Class using Mockito (with Spring Boot 1.3.8.RELEASE or lower)

package com.example.sample.unit.test.SampleUnitTestsSB_138.service.mockito;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import com.example.sample.unit.test.SampleUnitTestsSB_138.dao.ExampleDAO;
import com.example.sample.unit.test.SampleUnitTestsSB_138.service.ExampleService;

import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.equalTo;

// we don't have the @RunWith(SpringRunner.class) annotation -> we use the pure Mockito annotations
public class ExampleServiceTest {

	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// instantiates the subject of test and injects the mocked dependencies
	@InjectMocks // use to inject mocked objects in spring boot versions lower than 1.4
	private ExampleService exampleService;
	
	// mock the autowired dependency of the test subject	
	// we don't have the @MockBean in spring boot versions lower than 1.4 -> we use @Mock
	@Mock
	ExampleDAO exampleDAOMock;
	
	// expect values to be returned by the service
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
		
		// initializes the mocked objects and injects the mocks to the object with @InjectMocks 
		MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAMapWithAllNames() throws Exception {
		// you can use in static way or do a static import
		Mockito.doReturn(expectedNames).when(exampleDAOMock).findAll();
		
		// invokes the test subject that uses the mocked behaviors		
		Map<String,String> result = exampleService.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(expectedNames.size()));
		assertThat(result.get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(exampleDAOMock).findAll();
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldThrowASQLExceptionWhenDAOThrowsAnSQLException() throws Exception {
		SQLException expectedException = new SQLException("Some Expected DAO Exception");
		
		// should be before the test subject method invocation
		// indicates that the test case expects an exception of SQLException class with this message
		thrown.expect(SQLException.class);
		thrown.expectMessage(expectedException.getMessage());
								
		// forces to throw an exception from the service to test the controller's catch code
		Mockito.doThrow(expectedException).when(exampleDAOMock).findAll();
		
		// invokes the test subject that uses the mocked behaviors		
		// don't expect any assert because the service method should thrown an Exception
		exampleService.getAllNames();
				
		Mockito.verify(exampleDAOMock).findAll();		
	}
}

Unit Test for the Service Class using EasyMock

package com.example.sample.unit.test.SampleUnitTestsSB_141.service.easymock;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import com.example.sample.unit.test.SampleUnitTestsSB_141.dao.ExampleDAO;
import com.example.sample.unit.test.SampleUnitTestsSB_141.service.ExampleService;

@RunWith(EasyMockRunner.class)
public class ExampleServiceTest {
	
	// instantiates the subject of test and injects the mocked dependencies
	@TestSubject
	ExampleService exampleService = new ExampleService();
	
	// mock the autowired dependency of the test subject
	@Mock
	ExampleDAO exampleDAOMock;

	// used to assert and catch the expected exceptions thrown by the test subject
	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// expect values to be returned by the service
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
	}
	
	@Test
	public void getAllNamesWithValidArgumentsShouldReturnAMapWithAllNames() throws Exception {
		// you can use in static way or do a static import
		// mocks the expected behavior for the DAO in this test case
		// important: you will test only the logic and the coverage of the test subject so mock the dependecies for that
		EasyMock.expect(exampleDAOMock.findAll()).andReturn(expectedNames);
		// indicates to EasyMock that has to "record" the expected behavior of mock objects
		EasyMock.replay(exampleDAOMock);
		
		// invokes the test subject that uses the mocked behaviors		
		Map<String,String> result = exampleService.getAllNames();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(expectedNames.size()));
		assertThat(result.get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to EasyMock that verifies if the mocked objects were called
		EasyMock.verify(exampleDAOMock);
	}

	@Test
	public void getAllNamesWithValidArgumentsShouldThrowASQLExceptionWhenDAOThrowsAnSQLException() throws Exception {
		SQLException expectedException = new SQLException("Some Expected DAO Exception");

		// should be before the test subject method invocation
		// indicates that the test case expects an exception of SQLException class with this message
		thrown.expect(SQLException.class);
		thrown.expectMessage(expectedException.getMessage());
				
		// forces to throw an exception from the service to test the controller's catch code
		EasyMock.expect(exampleDAOMock.findAll()).andThrow(expectedException);
		EasyMock.replay(exampleDAOMock);
		
		// invokes the test subject that uses the mocked behaviors		
		// don't expect any assert because the service method should thrown an Exception
		exampleService.getAllNames();
				
		EasyMock.verify(exampleDAOMock);
	}	
}

Example – Test a Spring Boot JDBC DAO

DAO Class

package com.example.sample.unit.test.SampleUnitTestsSB_141.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class ExampleDAOImpl implements ExampleDAO {

	private static final Logger LOGGER = LoggerFactory.getLogger(ExampleDAOImpl.class);
	
	final static String QUERY_FIND_ALL = " SELECT * FROM TEST ";
	
	@Autowired
	DataSource dataSource;
	
	public Map<String,String> findAll() throws SQLException {
		Map<String,String> records = new HashMap<>();
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		
		try {
			connection = dataSource.getConnection();
			preparedStatement = connection.prepareStatement(QUERY_FIND_ALL);
			resultSet = preparedStatement.executeQuery();
			
			while (resultSet.next()) {
				records.put(resultSet.getString(1), resultSet.getString(2));
			}
			
			return records;
		} catch (SQLException sqle) {
			LOGGER.error("Error performing query", sqle);
			throw sqle;
		} finally {
			closeSQLObject(resultSet, ResultSet.class.getName());
			closeSQLObject(preparedStatement, PreparedStatement.class.getName());
			closeSQLObject(connection, Connection.class.getName());
		}
	}
	
	/**
	 * Closes the given SQL AutoCloseable object.
	 * @param sqlObject
	 * @param sqlObjectType
	 */
	private void closeSQLObject(final AutoCloseable sqlObject, final String sqlObjectType) {
		try {
			sqlObject.close();
		} catch (Exception e) {
			LOGGER.warn("Exception closing : {}", sqlObjectType);
		}
	}
}

Unit Test for the DAO Class using Mockito (with Spring Boot 1.4.1.RELEASE or higher)

package com.example.sample.unit.test.SampleUnitTestsSB_141.dao.mockito;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.sample.unit.test.SampleUnitTestsSB_141.dao.ExampleDAOImpl;

@RunWith(SpringRunner.class) // since 1.4.X version we can use this annotation to run the test using SB features
public class ExampleDAOImplTest {
	
	// include the query because if you change the query accidentally the test case will fail (it's a good checkpoint)
	final static String QUERY_FIND_ALL = " SELECT * FROM TEST ";
	
	// SpyBean instantiates the subject of test, injects the mocked dependencies and invokes the real object methods
	@SpyBean
	ExampleDAOImpl exampleDAOImpl;
	
	// mock the autowired dependency of the test subject		
	@MockBean
	DataSource dataSourceMock;
	
	// mocks the connection used by the DataSource mock
	@MockBean
	Connection connectionMock;
	// mocks the prepared statment used by the DataSource mock
	@MockBean
	PreparedStatement preparedStatementMock = null;
	// mocks the result set used by the DataSource mock
	@MockBean
	ResultSet resultSetMock = null;

	// used to assert and catch the expected exceptions thrown by the test subject
	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// expect values to be returned by the dao
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
		
		// we don't need initializes the mocked objects and their dependencies -> Spring Boot doing that 🙂 
		// MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void findAllWithValidArgumentsShouldReturnAMapWithAllNames() throws Exception {
		// you can use in static way or do a static import
		// mocks the expected behavior for the DAO in this test case
		// important: you will test only the logic and the coverage of the test subject so mock the dependencies for that
		Mockito.doReturn(connectionMock).when(dataSourceMock).getConnection();
		Mockito.doReturn(preparedStatementMock).when(connectionMock).prepareStatement(QUERY_FIND_ALL);
		Mockito.doReturn(resultSetMock).when(preparedStatementMock).executeQuery();
		
		// mocks the ResultSet iteration and sets the expect results
		// you can chain the expected behavior of the iteration
		Mockito.doReturn(true).doReturn(true).doReturn(true).doReturn(true).doReturn(true).doReturn(false).when(resultSetMock).next();
		Mockito.doReturn("1").doReturn("2").doReturn("3").doReturn("4").doReturn("5").when(resultSetMock).getString(1);
		Mockito.doReturn(expectedNames.get("1"))
			.doReturn(expectedNames.get("2"))
			.doReturn(expectedNames.get("3"))
			.doReturn(expectedNames.get("4"))
			.doReturn(expectedNames.get("5"))
			.when(resultSetMock).getString(2);
		
		// mocks the finally block
		Mockito.doNothing().when(resultSetMock).close(); // the close method is a void method so you don't expect any result
		Mockito.doNothing().when(preparedStatementMock).close();
		Mockito.doNothing().when(connectionMock).close();
		
		// invokes the test subject that uses the mocked behaviors		
		Map<String,String> result = exampleDAOImpl.findAll();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(expectedNames.size()));
		assertThat(result.get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(dataSourceMock).getConnection();
		// you should include Mockito.verify for each mocked method and object
	}

	@Test
	public void findAllWithValidArgumentsShouldThrowASQLExceptionWhenGetConnectionThrowsAnException() throws Exception {
		SQLException expectedException = new SQLException("Get Connection Exception");

		// should be before the test subject method invocation
		// indicates that the test case expects an exception of SQLException class with this message
		thrown.expect(SQLException.class);
		thrown.expectMessage(expectedException.getMessage());
				
		// forces to throw an exception from the service to test the controller's catch code
		Mockito.doThrow(expectedException).when(dataSourceMock).getConnection();
		
		// mocks the finally block
		Mockito.doNothing().when(resultSetMock).close(); // the close method is a void method so you don't expect any result
		Mockito.doNothing().when(preparedStatementMock).close();
		Mockito.doNothing().when(connectionMock).close();

		// invokes the test subject that uses the mocked behaviors		
		// don't expect any assert because the DAO method should thrown an Exception
		exampleDAOImpl.findAll();
				
		Mockito.verify(dataSourceMock).getConnection();
		// you should include Mockito.verify for each mocked method and object
	}	
}

Unit Test for the DAO Class using Mockito (with Spring Boot 1.3.8.RELEASE or lower)

package com.example.sample.unit.test.SampleUnitTestsSB_138.dao.mockito;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import com.example.sample.unit.test.SampleUnitTestsSB_138.dao.ExampleDAOImpl;

//we don't have the @RunWith(SpringRunner.class) annotation -> we use the pure Mockito annotations
public class ExampleDAOImplTest {
	
	// include the query because if you change the query accidentally the test case will fail (it's a good checkpoint)
	final static String QUERY_FIND_ALL = " SELECT * FROM TEST ";
	
	// instantiates the subject of test and injects the mocked dependencies
	@InjectMocks // use to inject mocked objects in spring boot versions lower than 1.4
	ExampleDAOImpl exampleDAOImpl;
	
	// mock the autowired dependency of the test subject	
	// we don't have the @MockBean in spring boot versions lower than 1.4 -> we use @Mock
	@Mock
	DataSource dataSourceMock;
	// mocks the connection used by the DataSource mock
	@Mock
	Connection connectionMock;
	// mocks the prepared statment used by the DataSource mock
	@Mock
	PreparedStatement preparedStatementMock = null;
	// mocks the result set used by the DataSource mock
	@Mock
	ResultSet resultSetMock = null;

	// used to assert and catch the expected exceptions thrown by the test subject
	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// expect values to be returned by the dao
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
		
		// initializes the mocked objects and injects the mocks to the object with @InjectMocks 
		MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void findAllWithValidArgumentsShouldReturnAMapWithAllNames() throws Exception {
		// you can use in static way or do a static import
		// mocks the expected behavior for the DAO in this test case
		// important: you will test only the logic and the coverage of the test subject so mock the dependencies for that
		Mockito.doReturn(connectionMock).when(dataSourceMock).getConnection();
		Mockito.doReturn(preparedStatementMock).when(connectionMock).prepareStatement(QUERY_FIND_ALL);
		Mockito.doReturn(resultSetMock).when(preparedStatementMock).executeQuery();
		
		// mocks the ResultSet iteration and sets the expect results
		// you can chain the expected behavior of the iteration
		Mockito.doReturn(true).doReturn(true).doReturn(true).doReturn(true).doReturn(true).doReturn(false).when(resultSetMock).next();
		Mockito.doReturn("1").doReturn("2").doReturn("3").doReturn("4").doReturn("5").when(resultSetMock).getString(1);
		Mockito.doReturn(expectedNames.get("1"))
			.doReturn(expectedNames.get("2"))
			.doReturn(expectedNames.get("3"))
			.doReturn(expectedNames.get("4"))
			.doReturn(expectedNames.get("5"))
			.when(resultSetMock).getString(2);
		
		// mocks the finally block
		Mockito.doNothing().when(resultSetMock).close(); // the close method is a void method so you don't expect any result
		Mockito.doNothing().when(preparedStatementMock).close();
		Mockito.doNothing().when(connectionMock).close();
		
		// invokes the test subject that uses the mocked behaviors		
		Map<String,String> result = exampleDAOImpl.findAll();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(expectedNames.size()));
		assertThat(result.get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to Mockito that verifies if the mocked objects were called
		Mockito.verify(dataSourceMock).getConnection();
		// you should include Mockito.verify for each mocked method and object
	}

	@Test
	public void findAllWithValidArgumentsShouldThrowASQLExceptionWhenGetConnectionThrowsAnException() throws Exception {
		SQLException expectedException = new SQLException("Get Connection Exception");

		// should be before the test subject method invocation
		// indicates that the test case expects an exception of SQLException class with this message
		thrown.expect(SQLException.class);
		thrown.expectMessage(expectedException.getMessage());
				
		// forces to throw an exception from the service to test the controller's catch code
		Mockito.doThrow(expectedException).when(dataSourceMock).getConnection();
		
		// mocks the finally block
		Mockito.doNothing().when(resultSetMock).close(); // the close method is a void method so you don't expect any result
		Mockito.doNothing().when(preparedStatementMock).close();
		Mockito.doNothing().when(connectionMock).close();

		// invokes the test subject that uses the mocked behaviors		
		// don't expect any assert because the DAO method should thrown an Exception
		exampleDAOImpl.findAll();
				
		Mockito.verify(dataSourceMock).getConnection();
		// you should include Mockito.verify for each mocked method and object
	}	
}

Unit Test for the DAO Class using EasyMock

package com.example.sample.unit.test.SampleUnitTestsSB_141.dao.easymock;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import com.example.sample.unit.test.SampleUnitTestsSB_141.dao.ExampleDAOImpl;

@RunWith(EasyMockRunner.class)
public class ExampleDAOImplTest {
	// include the query because if you change the query accidentally the test case will fail (it's a good checkpoint)
	final static String QUERY_FIND_ALL = " SELECT * FROM TEST ";
	
	// instantiates the subject of test and injects the mocked dependencies
	@TestSubject
	ExampleDAOImpl exampleDAOImpl = new ExampleDAOImpl();
	
	// mocks the autowired dependency of the test subject
	@Mock
	DataSource dataSourceMock;
	// mocks the connection used by the DataSource mock
	@Mock
	Connection connectionMock;
	// mocks the prepared statment used by the DataSource mock
	@Mock
	PreparedStatement preparedStatementMock = null;
	// mocks the result set used by the DataSource mock
	@Mock
	ResultSet resultSetMock = null;

	// used to assert and catch the expected exceptions thrown by the test subject
	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	// expect values to be returned by the dao
	private Map<String,String> expectedNames;
	
	// executed before each test case method -> initializes the expected values
	@Before
	public void setUp() {
		expectedNames = new HashMap<>();
		
		for (int i = 1; i < 6; i++) {
			expectedNames.put(String.valueOf(i), "Name "+ i);
		}
	}
	
	@Test
	public void findAllWithValidArgumentsShouldReturnAMapWithAllNames() throws Exception {
		// you can use in static way or do a static import
		// mocks the expected behavior for the DAO in this test case
		// important: you will test only the logic and the coverage of the test subject so mock the dependencies for that
		EasyMock.expect(dataSourceMock.getConnection()).andReturn(connectionMock);
		EasyMock.expect(connectionMock.prepareStatement(QUERY_FIND_ALL)).andReturn(preparedStatementMock);
		EasyMock.expect(preparedStatementMock.executeQuery()).andReturn(resultSetMock);
		
		// mocks the ResultSet iteration and sets the expect results
		EasyMock.expect(resultSetMock.next()).andReturn(true);
		EasyMock.expect(resultSetMock.getString(1)).andReturn("1");
		EasyMock.expect(resultSetMock.getString(2)).andReturn(expectedNames.get("1"));
		EasyMock.expect(resultSetMock.next()).andReturn(true);
		EasyMock.expect(resultSetMock.getString(1)).andReturn("2");
		EasyMock.expect(resultSetMock.getString(2)).andReturn(expectedNames.get("2"));
		EasyMock.expect(resultSetMock.next()).andReturn(true);
		EasyMock.expect(resultSetMock.getString(1)).andReturn("3");
		EasyMock.expect(resultSetMock.getString(2)).andReturn(expectedNames.get("3"));
		EasyMock.expect(resultSetMock.next()).andReturn(true);
		EasyMock.expect(resultSetMock.getString(1)).andReturn("4");
		EasyMock.expect(resultSetMock.getString(2)).andReturn(expectedNames.get("4"));
		EasyMock.expect(resultSetMock.next()).andReturn(true);
		EasyMock.expect(resultSetMock.getString(1)).andReturn("5");
		EasyMock.expect(resultSetMock.getString(2)).andReturn(expectedNames.get("5"));
		EasyMock.expect(resultSetMock.next()).andReturn(false);
		
		// mocks the finally block
		resultSetMock.close(); // the close method is a void method so you don't expect any result
		EasyMock.expectLastCall(); // for the void method use expectLastCall
		preparedStatementMock.close();
		EasyMock.expectLastCall();
		connectionMock.close();
		EasyMock.expectLastCall();
		
		// indicates to EasyMock that has to "record" the expected behavior of mock objects
		EasyMock.replay(dataSourceMock, connectionMock, preparedStatementMock, resultSetMock);
		
		// invokes the test subject that uses the mocked behaviors		
		Map<String,String> result = exampleDAOImpl.findAll();
		
		// assert the expected results of the test case
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(expectedNames.size()));
		assertThat(result.get("1"), equalTo(expectedNames.get("1"))); // should be "Name 1"
		assertThat(result.get("1"), equalTo("Name 1")); // another way for the previous assertion
		assertThat(result.get("2"), equalTo(expectedNames.get("2")));
		assertThat(result.get("3"), equalTo(expectedNames.get("3")));
		assertThat(result.get("4"), equalTo(expectedNames.get("4")));
		assertThat(result.get("5"), equalTo(expectedNames.get("5")));
		
		// indicates to EasyMock that verifies if the mocked objects were called
		EasyMock.verify(dataSourceMock, connectionMock, preparedStatementMock, resultSetMock);
	}

	@Test
	public void findAllWithValidArgumentsShouldThrowASQLExceptionWhenGetConnectionThrowsAnException() throws Exception {
		SQLException expectedException = new SQLException("Get Connection Exception");

		// should be before the test subject method invocation
		// indicates that the test case expects an exception of SQLException class with this message
		thrown.expect(SQLException.class);
		thrown.expectMessage(expectedException.getMessage());
				
		// forces to throw an exception from the service to test the controller's catch code
		EasyMock.expect(dataSourceMock.getConnection()).andThrow(expectedException);
		
		// mocks the finally block
		resultSetMock.close(); // the close method is a void method so you don't expect any result
		EasyMock.expectLastCall(); // for the void method use expectLastCall
		preparedStatementMock.close();
		EasyMock.expectLastCall();
		connectionMock.close();
		EasyMock.expectLastCall();

		EasyMock.replay(dataSourceMock, connectionMock, preparedStatementMock, resultSetMock);
		
		// invokes the test subject that uses the mocked behaviors		
		// don't expect any assert because the DAO method should thrown an Exception
		exampleDAOImpl.findAll();
				
		EasyMock.verify(dataSourceMock);
	}	
}

Useful documentation and examples
Online Training:

About TDD:

About Spring Boot Test:

About Mockito

About system-rules dependency:

Final notes
The Application and their Unit Tests were tested with Spring Boot versions: 1.5.4.RELEASE, 1.4.1.RELEASE and 1.3.8.RELEASE (without ServletInitiliazer class)

You can get the complete code from my public GitHub repository:
https://github.com/Gabotto/SampleUnitTests

Let me know if you have any problem, comment or new ideas:
WordPress: https://gabelopment.wordpress.com/
Email: gabelopment@gmail.com

Also you can find me at Upwork

See you soon with more development notes…