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…