To unit test Spring Boot application we need to use spring-boot-starter-test, which imports both Spring Boot test modules as well as JUnit Jupiter, AssertJ, Hamcrest, and a number of other useful libraries.
spring-boot-starter-test uses spring-boot-test (see core tutorial) and spring-boot-test-autoconfigure (auto-configuration for tests).
Spring Boot provides a @SpringBootTest annotation, which can be used as an alternative to the standard spring-test @ContextConfiguration annotation when we need Spring Boot features.
Example
pom.xml<project .....> <modelVersion>4.0.0</modelVersion>
<groupId>com.logicbig.example</groupId> <artifactId>boot-application-unit-testing</artifactId> <version>1.0-SNAPSHOT</version>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent>
<properties> <java.version>1.8</java.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> </project>
Boot example application
@Service
public class OrderService {
public String placeOrders(List<Order> orders) {
//just a dummy service
return orders.size() + " orders placed";
}
}
public class Order {
private String item;
private int qty;
public Order(String item, int qty) {
this.item = item;
this.qty = qty;
}
public String getItem() {
return item;
}
public int getQty() {
return qty;
}
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ShoppingCart {
@Autowired
private OrderService orderService;
private List<Order> orders = new ArrayList<>();
public void addItem(String name, int qty) {
orders.add(new Order(name, qty));
}
public String checkout() {
String msg = orderService.placeOrders(orders);
orders.clear();
return msg;
}
}
@SpringBootApplication
public class AppMain {
public static void main(String[] args) {
SpringApplication.run(AppMain.class, args);
}
}
Writing JUnit test
package com.logicbig.example;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppMain.class)
public class ShoppingCartTest {
@Autowired
private ShoppingCart shoppingCart;
@Test
public void testCheckout() {
shoppingCart.addItem("Item1", 3);
shoppingCart.addItem("item2", 5);
String result = shoppingCart.checkout();
Assert.assertEquals("2 orders placed", result);
}
}
d:\boot-application-unit-test>mvn test -Dtest=ShoppingCartTest [INFO] Scanning for projects... [INFO] [INFO] ---------< com.logicbig.example:boot-application-unit-testing >--------- [INFO] Building boot-application-unit-testing 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ boot-application-unit-testing --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ boot-application-unit-testing --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ boot-application-unit-testing --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ boot-application-unit-testing --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ boot-application-unit-testing --- [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- 01:34:19.132 [main] DEBUG org.springframework.test.context.junit4.SpringJUnit4ClassRunner - SpringJUnit4ClassRunner constructor called with [class com.logicbig.example.ShoppingCartTest] 01:34:19.139 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate] 01:34:19.163 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)] 01:34:19.231 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.logicbig.example.ShoppingCartTest] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper] 01:34:19.271 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.logicbig.example.ShoppingCartTest], using SpringBootContextLoader 01:34:19.280 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.logicbig.example.ShoppingCartTest]: class path resource [com/logicbig/example/ShoppingCartTest-context.xml] does not exist 01:34:19.282 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.logicbig.example.ShoppingCartTest]: class path resource [com/logicbig/example/ShoppingCartTestContext.groovy] does not exist 01:34:19.282 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.logicbig.example.ShoppingCartTest]: no resource found for suffixes {-context.xml, Context.groovy}. 01:34:19.335 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.logicbig.example.ShoppingCartTest] 01:34:19.488 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.logicbig.example.ShoppingCartTest]: using defaults. 01:34:19.488 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] 01:34:19.499 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [javax/servlet/ServletContext] 01:34:19.502 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource] 01:34:19.503 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute] 01:34:19.503 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@433defed, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@2a693f59, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@3f4faf53, org.springframework.test.context.support.DirtiesContextTestExecutionListener@7fd50002, org.springframework.test.context.event.EventPublishingTestExecutionListener@533bda92, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@304bb45b, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@723ca036, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@25be7b63, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@28dcca0c, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@45d84a20] 01:34:19.511 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.logicbig.example.ShoppingCartTest] 01:34:19.515 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.logicbig.example.ShoppingCartTest] 01:34:19.569 [main] DEBUG org.springframework.test.context.junit4.SpringJUnit4ClassRunner - SpringJUnit4ClassRunner constructor called with [class com.logicbig.example.ShoppingCartTest] 01:34:19.569 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate] 01:34:19.571 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)] 01:34:19.576 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.logicbig.example.ShoppingCartTest] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper] 01:34:19.578 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.logicbig.example.ShoppingCartTest], using SpringBootContextLoader 01:34:19.582 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.logicbig.example.ShoppingCartTest]: class path resource [com/logicbig/example/ShoppingCartTest-context.xml] does not exist 01:34:19.584 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.logicbig.example.ShoppingCartTest]: class path resource [com/logicbig/example/ShoppingCartTestContext.groovy] does not exist 01:34:19.586 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.logicbig.example.ShoppingCartTest]: no resource found for suffixes {-context.xml, Context.groovy}. 01:34:19.593 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.logicbig.example.ShoppingCartTest] 01:34:19.598 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.logicbig.example.ShoppingCartTest]: using defaults. 01:34:19.600 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] 01:34:19.605 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [javax/servlet/ServletContext] 01:34:19.608 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource] 01:34:19.610 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute] 01:34:19.610 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@1b66c0fb, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@3e0e1046, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@24c1b2d2, org.springframework.test.context.support.DirtiesContextTestExecutionListener@7dc19a70, org.springframework.test.context.event.EventPublishingTestExecutionListener@508dec2b, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@1e4f4a5c, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@37313c65, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@465232e9, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@798162bc, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@1df8da7a] 01:34:19.611 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.logicbig.example.ShoppingCartTest] 01:34:19.611 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.logicbig.example.ShoppingCartTest] 01:34:19.755 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.logicbig.example.ShoppingCartTest] 01:34:19.756 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.logicbig.example.ShoppingCartTest] [INFO] Running com.logicbig.example.ShoppingCartTest 01:34:19.761 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.logicbig.example.ShoppingCartTest] 01:34:19.761 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.logicbig.example.ShoppingCartTest] 01:34:19.764 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.logicbig.example.ShoppingCartTest] 01:34:19.765 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.logicbig.example.ShoppingCartTest] 01:34:19.772 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@58594a11 testClass = ShoppingCartTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@2a3888c1 testClass = ShoppingCartTest, locations = '{}', classes = '{class com.logicbig.example.AppMain, class com.logicbig.example.AppMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@28701274, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@62379589, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@7586beff, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@15de0b3c], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]], class annotated with @DirtiesContext [false] with mode [null]. 01:34:19.776 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.logicbig.example.ShoppingCartTest] 01:34:19.776 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.logicbig.example.ShoppingCartTest] 01:34:19.782 [main] DEBUG org.springframework.test.context.support.DependencyInjectionTestExecutionListener - Performing dependency injection for test context [[DefaultTestContext@58594a11 testClass = ShoppingCartTest, testInstance = com.logicbig.example.ShoppingCartTest@27adc16e, testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@2a3888c1 testClass = ShoppingCartTest, locations = '{}', classes = '{class com.logicbig.example.AppMain, class com.logicbig.example.AppMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@28701274, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@62379589, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@7586beff, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@15de0b3c], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]]. 01:34:19.818 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=-1}
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.5.RELEASE)
2020-03-17 01:34:20.212 INFO 14508 --- [ main] com.logicbig.example.ShoppingCartTest : No active profile set, falling back to default profiles: default 2020-03-17 01:34:20.883 INFO 14508 --- [ main] com.logicbig.example.ShoppingCartTest : Started ShoppingCartTest in 1.058 seconds (JVM running for 2.55) [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.79 s - in com.logicbig.example.ShoppingCartTest [INFO] [INFO] Results: [INFO] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.415 s [INFO] Finished at: 2020-03-17T01:34:22-05:00 [INFO] ------------------------------------------------------------------------
In above example we used @SpringBootTest(classes = AppMain.class) . If 'classes' attribute is not specified, @SpringBootTest annotation (and other Spring Boot's @*Test annotations) search for the primary configuration automatically. The search algorithm works up from the package that contains the test until it finds a class annotated with @SpringBootApplication or @SpringBootConfiguration.
Example ProjectDependencies and Technologies Used: - Spring Boot 2.2.5.RELEASE
- spring-boot-starter-test : Starter for testing Spring Boot applications with libraries including
JUnit, Hamcrest and Mockito.
- JDK 1.8
- Maven 3.5.4
|
|