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:
- http://agiledata.org/essays/tdd.html
- https://dzone.com/articles/5-more-best-practices-for-test-driven-development
- https://technologyconversations.com/2013/12/24/test-driven-development-tdd-best-practices-using-java-examples-2/
- http://enterprisecraftsmanship.com/2015/08/03/tdd-best-practices/
About Spring Boot Test:
- https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
- https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4
About Mockito
- http://site.mockito.org/
- https://en.wikipedia.org/wiki/Mock_object
- https://en.wikipedia.org/wiki/Mockito
- http://stackoverflow.com/questions/14440270/how-does-mockito-when-invocation-work
- https://dzone.com/articles/mockito-pros-cons-and-best
- https://gojko.net/2009/10/23/mockito-in-six-easy-examples/S
- https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/
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…