Close

Spring Boot - Application Unit Testing with @SpringBootTest

[Last Updated: Aug 11, 2020]

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 Project

Dependencies 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

Spring Boot - Application Unit Testing Select All Download
  • boot-application-unit-testing
    • src
      • main
        • java
          • com
            • logicbig
              • example
      • test
        • java
          • com
            • logicbig
              • example
                • ShoppingCartTest.java

    See Also