Spring Boot Test
Spring Boot provides many tools that enable a developer to unit test an application with simple annotations and minimal configuration.
Most developers will just use the spring-boot-starter-test ‘Starter’ which imports both Spring Boot test modules as well has JUnit, AssertJ, Hamcrest and a number of other useful libraries.
Maven Dependency
To start, it is simple to add a maven dependency to the project, shown as:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
You can find the latest version of the dependency here.
With just one dependency added to the pom.xml file, you can find the following provided libraries added to your project:
- JUnit : The most popular framework 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
Excellent, all this with just one dependency added.
Simple Test Application
Now, let us start quickly by setting up a simple application for performing a very simple unit test on a controller API. Our main class will look like:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Now that Spring Boot application main is ready, let’s move to writing a simple Rest Controller using @RestController annotation.
@RestController
@EnableAutoConfiguration
public class HelloWorld {
@RequestMapping("/")
String getHelloWorld() {
return "Hello World!";
}
}
Finally, we get our test running as:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
public class DemoApplicationTests {
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = standaloneSetup(new HelloWorld()).build();
}
@Test
public void testSayHelloWorld() throws Exception {
this.mockMvc.perform(get("/")
.accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"));
}
}
Here, we build a MockMvc by registering one or more @Controller's instances and configuring Spring MVC infrastructure programmatically. This allows full control over the instantiation and initialization of controllers, and their dependencies.
Spring Data JPA Tests
Simple Annotation, @DataJpaTest can be used if a JPA application needs to be tested. By default, it will configure an in-memory embedded database, scan for @Entity classes, and configure Spring Data JPA repositories. Regular @Component beans will not be loaded into the ApplicationContext.
Data JPA tests are transactional and rollback at the end of each test by default. This can be changed with a single setting if that is what you want.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {
}
Data JPA tests can also inject a TestEntityManager, which can be used for a Database interaction. Let’s see that next.
import org.junit.*;
import org.junit.runner.*;
import org.springframework.boot.test.autoconfigure.orm.jpa.*;
import static org.assertj.core.api.Assertions.*;
@RunWith(SpringRunner.class)
@DataJpaTest
public class DiscoverRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
public void testExample() throws Exception {
this.entityManager.persist(new User("liran", "1234"));
User user = this.repository.findByUsername("liran");
assertThat(user.getUsername()).isEqualTo("liran");
assertThat(user.getVin()).isEqualTo("1234");
}
}
Testing the Main class
In Spring Boot, there is also an option to test the Main class and to pass any required arguments to the main() method. Let’s see this in action.
Usually, the following is sufficient to test that the application context starts up.
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTests {
@Test public void contextLoads() {
}
}
However, if we want to directly test Application.main, we can also test it this way:
public class ApplicationTest {
@Test public void test() {
Application.main(new String[]{
"--spring.main.web-environment=false",
"--spring.autoconfigure.exclude=another",
// Override any other environment properties according to your needs
});
}
}
Mock objects
In unit test, a test double (object to be mocked) is a replacement of a dependent component (collaborator) of the object under test. With mocking, the purpose is to mimic the collaborator to make the object under test think that it is actually using the collaborator.
Based on the role played during testing, there can be different types of test doubles, and mock object is one of them. Some other types are dummy object, fake object, and stub.
What makes a mock object different from the others is that it uses behavior verification. It means that the mock object verifies that it (the mock object) is being used correctly by the object under test. If the verification succeeds, it can be considered that the object under test will correctly use the real collaborator.
If we consider a ProductService class,
public class ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public boolean buy(Product product, int orderedQuantity) throws InsufficientProductsException {
boolean transactionStatus=false;
int availableQuantity =
productDao.getAvailableProducts(product);
if (orderedQuantity > availableQuantity) {
throw new InsufficientProductsException();
}
productDao.orderProduct(product, orderedQuantity);
transactionStatus=true;
return transactionStatus;
}
}
What we now need is to unit test ProductService. But as you can see, ProductService is composed of ProductDao, whose implementations we don’t have yet.
We can use Mockito, which is a mocking framework for unit tests written in Java. It is an open source framework available at github.
In unit tests, we should not to be bothered what the implementation is doing. What we want is to test that our ProductService is behaving as expected and that it is able to correctly use its collaborators. For that, we will mock ProductDao and Product using Mockito.
Let us put this in action.
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class MockCreationTest {
private ProductDao productDao;
private Product product;
@Before
public void setupMock() {
product = mock(Product.class);
productDao = mock(ProductDao.class);
}
@Test
public void testMockCreation(){
assertNotNull(product);
assertNotNull(productDao);
}
}
Conclusion
The Mockito library is a very large and mature mocking library. It is very popular to use for mocking objects in unit tests. Mockito is popular because it is easy to use, and very versatile. Mocking in unit testing is extensively used in Enterprise Application Development with Spring.
By using Mockito, we can replace the @Autowired components in the class we want to test with mock objects. We will be unit testing controllers by injecting mock services. We will also be setting up services to use mock DAOs to unit test the service layer. To unit test the DAO layer, we will mock the database APIs. The list is endless, and it seems that the capabilities of mocking are endless as well.
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment