Overview of spring boot unit and integration testing

Jiedao jdon 2021-05-04 18:54:38
overview spring boot unit integration


Unit and integration testing is an integral part of your daily life as a developer . Especially for Spring Boot for , Novices writing meaningful tests for their applications is an obstacle :

  • Where to start my testing work ?
  • Spring Boot How to help me write efficient tests ?
  • Which libraries should I use ?

Through this blog , You'll learn about how unit boot and integration testing work with Spring Boot An overview of working together . most important of all , You will learn Spring First of all, focus on the functions and Libraries . This article acts as an aggregator , In many places , You can find links to other articles and guides , These articles and guides describe these concepts in more detail .

 

Use Spring Boot Unit test

Unit testing lays the foundation for your testing strategy . You use Spring Initializr Every one of the guides Spring Boot Projects have a solid foundation for writing unit tests . There's almost nothing to set up , because Spring Boot Starter Test Contains all the necessary building blocks .

In addition to inclusion and management Spring Test Out of version , this Spring Boot Starter Include and manage versions of the following Libraries :

  • JUnit 4/5
  • Mockito
  • Assertions library , Such as AssertJ,Hamcrest,JsonPath etc. .

Most of the time , Your unit tests don't need any specific Spring Boot or Spring Test function , Because they only depend on JUnit and Mockito.

Using unit tests , You can test it alone *Service class , Simulation, for example Mock Each collaborator of the class to be tested :

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
 
import java.math.BigDecimal;
 
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
 
@ExtendWith(MockitoExtension.class) // register the Mockito extension
public class PricingServiceTest {
 
  @Mock // // Instruct Mockito to mock this object
  private ProductVerifier mockedProductVerifier;
 
  @Test
  public void shouldReturnCheapPriceWhenProductIsInStockOfCompetitor() {
    when(mockedProductVerifier.isCurrentlyInStockOfCompetitor("AirPods"))
      .thenReturn(true); //Specify what boolean value to return
 
    PricingService cut = new PricingService(mockedProductVerifier);
 
    assertEquals(new BigDecimal("99.99"), cut.calculatePrice("AirPods"));
  }
}

From above import As you can see in the test class section of ,Spring Not at all import Come in . therefore , You can apply to any other Java Technology and knowledge of unit testing for applications .

therefore , It's important to learn JUnit 4/5 and Mockito Basic knowledge of , To make the most of your unit tests .

For some parts of the application , Unit testing doesn't bring many benefits . Persistence layer or test HTTP The client is a good example . Test these parts of the application , In the end, it will almost duplicate your implementation , Because you have to simulate a lot of interaction with other classes .

A better way here is to use slicing Spring Context, You can use Spring Boot Test annotations easily auto configure it .

 

Using sliced Spring Context testing

On top of traditional unit testing , You can use Spring Boot Write for specific parts of the application ( section ) Test of .SpringTestContext The framework and Spring Boot Together, we will Spring Context Tailor... With enough components for a particular test Spring Context.

The purpose of these tests is to test specific parts of the application separately without starting the entire application . This can shorten the test execution time , It also reduces the need for a large number of test settings .

How to name such tests ? In my submission , They don't degrade in unit testing or integration testing categories 100%. Some developers call them unit tests , Because they, for example, test a controller independently . Other developers classify them as integration tests , Because it involves Spring Support . No matter how you name it , At least make sure there is a consistent understanding in the team .

Spring Boot Lots of annotations are provided to test the isolation of different parts of your application :@JsonTest,@WebMvcTest,@DataMongoTest,@JdbcTest, etc. .

They all automatically configure slicing Spring,TestContext And only those related to specific parts of the test application Spring Bean. I've devoted myself to the whole article Introduces the most common of these annotations , And explain their usage .

Two of the most important notes ( Consider learning them first ) yes :

There are also comments that can be used for more subdivisions of your application :

You can always explicitly import components in the following ways @Import Or define other Spring Bean To enrich the autoconfiguration context of the test @TestConfiguration:

@WebMvcTest(PublicController.class)
class PublicControllerTest {
 
  @Autowired
  private MockMvc mockMvc;
 
  @Autowired
  private MeterRegistry meterRegistry;
 
  @MockBean
  private UserService userService;
 
  @TestConfiguration
  static class TestConfig {
 
    @Bean
    public MeterRegistry meterRegistry() {
      return new SimpleMeterRegistry();
    }
 
  } 
}

 

JUnit 4 And JUnit 5 trap

In response to a Stack Overflow When you have a problem with , One of the big pitfalls I often encounter is in the same test JUnit 4 and JUnit 5( More specifically ,JUnit Jupiter) Mixing . Use different... In the same test class JUnit Version of API Can cause unexpected output and failure .

It's important to pay attention to importing import, In especial @Test notes :

// JUnit 4
import org.junit.Test;
 
// JUnit Jupiter (part of JUnit 5)
import org.junit.jupiter.api.Test;

about JUnit 4 Other indicators are :@RunWith,@Rule,@ClassRule,@Before,@BeforeClass,@After,@AfterClass.

To avoid accidental mixing of different JUnit edition , Excluding them from a project helps you always choose the right import :

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>org.junit.vintage</groupId>
      <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
  </exclusions>
</dependency>

except Spring Boot Starter Test outside , Other test dependencies may also include older versions of JUnit:

<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>${testcontainers.version}</version>
  <exclusions>
    <exclusion>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </exclusion>
  </exclusions>
</dependency>

In order to avoid including in the future any ( Accidental )JUnit 4 Dependency relationship , have access to Maven Enforcer plug-in unit It is defined as forbidden dependency . Once someone includes a new test dependency , This dependency will temporarily pull JUnit 4, This will make the build fail .

Please note that , from Spring Boot 2.4.0 Start ,Spring Boot Starter Test Dependencies vintage-engine By default, it no longer contains .

 

Use Spring Boot Conduct integration test

Use integration testing , You can usually combine multiple components of a test application . in the majority of cases , You will use... For this @SpringBootTest notes , And use or access your application from outside .

@SpringBootTest The entire application context will be populated for your test . When using , Know it webEnvironment Attributes are important . If you do not specify this property , This type of test will not start the embedded Servlet Containers ( for example Tomcat), It's using simulation Servlet Environmental Science . therefore , Your application will not be accessible on the local port .

You can specify by DEFINE_PORT Or to override this behavior RANDOM_PORT:

// or DEFINED_PORT
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)

For booting embedded Servlet Integration testing of containers , You can inject the port of the application and use TestRestTemplateWebTestClient Or access it from the outside :

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class ApplicationTests {
 
  @LocalServerPort
  private Integer port;
 
  @Autowired
  private TestRestTemplate testRestTemplate;
 
  @Test
  void accessApplication() {
    System.out.println(port);
  }
}

because SpringTestContext The framework will fill in the entire application context , So you have to make sure that there are all the infrastructure components that you depend on ( for example , database , Message delivery queues, etc ).

This is it. Testcontainer Where it works . The test container will manage any Docker The life cycle of the container :

@Testcontainers
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class ApplicationIT {
 
  @Container
  public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer()
    .withPassword("inmemory")
    .withUsername("inmemory");
 
  @DynamicPropertySource
  static void postgresqlProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
    registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
    registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
  }
 
  @Test
  public void contextLoads() {
  }
 
}

Once your application communicates with other systems , You need a solution to simulate HTTP signal communication . This is a very common situation , For example, when an application starts from a remote REST API or OAuth2 Access token to get data . With the help of WireMock, You can stub and prepare HTTP Response to simulate the presence of a remote system .

Besides ,SpringTestContext The framework has an ingenious function , You can cache and reuse contexts that have already been started . This can help Reduce build time And greatly improve your feedback cycle .

 

Use Spring Boot Do end-to-end testing

End to end (E2E) The purpose of the test is to verify the system from the user's point of view . This includes testing for major user journeys ( for example , Place an order or create a new customer ). Compared to integration testing , This type of testing usually involves the user interface ( If any ).

You can also , in the light of dev or staging The deployed version of the application on the environment executes E2E test .

For using server-side rendering ( for example Thymeleaf) Or self-contained system approach ( from Spring Boot The back end provides the front end ) Applications for , You can use @SpringBootTest These tests .

Once you need to interact with the browser ,Selenium It's usually the default choice . If you've been with Selenium Worked together for a while , You may find yourself implementing the same helper function over and over again . In order to get a better developer experience and reduce the headache of writing tests involving browser interaction , Please consider using Selenide.Selenide yes Selenium low-level API The abstraction above , For writing stable and concise browser tests .

The following test shows how to use Selenide Access and test Spring Boot The public page of the application :

@Testcontainers
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class BookStoreTestcontainersWT {
 
  @LocalServerPort
  private Integer port;
 
  @Test
  public void shouldDisplayBook() {
 
    Configuration.timeout = 2000;
    Configuration.baseUrl = "http://localhost:" + port;
 
    open("/book-store");
 
    $(By.id("all-books")).shouldNot(Condition.exist);
    $(By.id("fetch-books")).click();
    $(By.id("all-books")).shouldBe(Condition.visible);
  }
}

For you to start E2E Infrastructure components for testing ,Testcontainers Playing an important role again . If you have to start multiple Docker Containers , be Testcontainers Of Docker Compose modular It will come in handy :

public static DockerComposeContainer<?> environment =
  new DockerComposeContainer<>(new File("docker-compose.yml"))
    .withExposedService("database_1", 5432, Wait.forListeningPort())
    .withExposedService("keycloak_1", 8080, Wait.forHttp("/auth").forStatusCode(200)
      .withStartupTimeout(Duration.ofSeconds(30)))
    .withExposedService("sqs_1", 9324, Wait.forListeningPort());

Generalization

Spring Boot Excellent support for unit testing and integration testing . Because each Spring Boot The projects include Spring Boot Starter Test, So it makes testing a first-class citizen . This entry program provides you with a basic test toolbox with a basic test library .

most important of all ,Spring Boot Test annotations make it easy to write tests on different parts of an application . You will get TestContext Only related Spring Bean It's made to measure Spring.

Be familiar with Spring Boot Unit and integration testing of the project , Consider the following steps :

版权声明
本文为[Jiedao jdon]所创,转载请带上原文链接,感谢
https://javamana.com/2021/05/20210504185015039V.html

  1. Prototype与JQuery对比
  2. Three ways of data transmission between threads in Java and source code display
  3. Jdon causes 99% of CPU and Tomcat dies -- banq replies
  4. docker 原理之 user namespace(下)
  5. Simulating AOP injection with domain events
  6. Spring 3.1 finally adds cache support
  7. Comparison between prototype and jquery
  8. User namespace of docker principle (2)
  9. The way to learn java IO stream and XML
  10. Why does a seemingly correct code cause the Dubbo thread pool to be full
  11. 0 基础 Java 自学之路(2021年最新版)
  12. 0 basic Java self study road (latest version in 2021)
  13. c#—基础拾遗(1) 面向对象
  14. C - basic information (1) object oriented
  15. 技术分享|SQL和 NoSQL数据库之间的差异:MySQL(VS)MongoDB
  16. Technology sharing differences between SQL and NoSQL databases: MySQL (VS) mongodb
  17. PHP教程/面向对象-3~构造函数和析构函数
  18. Spring Cloud的Feign客户端入门
  19. 优化Spring Boot应用的Docker打包速度
  20. PHP tutorial / object oriented - 3 ~ constructor and destructor
  21. Introduction to feign client of spring cloud
  22. Optimizing docker packaging speed of spring boot application
  23. 尚硅谷宋红康Java基础教程2019版
  24. 尚硅谷宋红康Java基础教程2019版
  25. Song Hongkang Java foundation course 2019
  26. Song Hongkang Java foundation course 2019
  27. Redis 6 的多线程
  28. Multithreading of redis 6
  29. SpringCloud-微服务架构编码构建
  30. SpringCloud-微服务架构编码构建
  31. Linux作业控制
  32. Coding construction of springcloud microservice architecture
  33. Java中几个常用并发队列比较 | Baeldung
  34. 为什么Java后端在创业企业中并不流行? -reddit
  35. Coding construction of springcloud microservice architecture
  36. Linux job control
  37. Comparison of several common concurrent queues in Java
  38. Why is java backend not popular in start-ups- reddit
  39. docker 资源限制之 cgroup
  40. 大数据环境: hadoop和jdk部署
  41. CGroup of docker resource limitation
  42. Big data environment: Hadoop and JDK deployment
  43. Spring与Hibernate与JPA的整合(详细配置和源码)
  44. Integration of spring, hibernate and JPA (detailed configuration and source code)
  45. 《精通JPA与Hibernate:Java对象持久化技术详解》的源代码下载
  46. 《精通JPA与Hibernate:Java对象持久化技术详解》的源代码下载
  47. "Proficient in JPA and Hibernate: Java Object Persistence technology" source code download
  48. "Proficient in JPA and Hibernate: Java Object Persistence technology" source code download
  49. Redis、Kafka或RabbitMQ:选择哪个作为微服务消息代理? - otonomo
  50. Java Stream和Collection比较:何时以及如何从Java API返回Stream而不是集合Collection? - TomaszKiełbowicz
  51. 如何在SpringBoot中使用Hibernate @NaturalId?
  52. RPC框架设计----NIO编程通道(Channel)
  53. The use of jquery
  54. Redis, Kafka or rabbitmq: which one to choose as the micro service message broker- otonomo
  55. Comparison of Java stream and collection: when and how to return stream instead of collection from Java API- TomaszKie ł bowicz
  56. How to use hibernate @ naturalid in springboot?
  57. RPC framework design -- NiO programming channel
  58. RPC框架设计----NIO编程Selector (选择器)
  59. RPC framework design -- NiO programming selector
  60. Linux centos重启命令