美文网首页
Junit Test(从junit -> spring-test

Junit Test(从junit -> spring-test

作者: Bystander_1996 | 来源:发表于2024-06-29 23:37 被阅读0次

Junit

使用方式

Junit4

  1. 引入依赖包
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>
  1. 编写测试类
 import org.junit.Test;
 import static org.junit.Assert.assertEquals;
 
 public class CalculatorTest {
 
     @Test
     public void testAdd() {
         Calculator calculator = new Calculator();
         int result = calculator.add(2, 3);
         assertEquals(5, result);
     }
 }
  1. 常用注解
   @Test: 标记一个方法为测试方法。
   @Before: 每个测试方法之前运行。
   @After: 每个测试方法之后运行。
   @BeforeClass: 在所有测试方法之前运行,仅运行一次。
   @AfterClass: 在所有测试方法之后运行,仅运行一次。

Junit5

  1. 引入依赖包
   <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter-api</artifactId>
       <version>5.10.2</version>
       <scope>test</scope>
   </dependency>
   <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter-engine</artifactId>
       <version>5.10.2</version>
       <scope>test</scope>
   </dependency>
   
   <!-- 或者只引入下面的就可以了-->
   <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter</artifactId>
       <version>5.10.2</version>
       <scope>test</scope>
   </dependency>
  1. 编写测试类
   import org.junit.jupiter.api.Test;
   import static org.junit.jupiter.api.Assertions.assertEquals;
   
   public class CalculatorTest {
   
       @Test
       public void testAdd() {
           Calculator calculator = new Calculator();
           int result = calculator.add(2, 3);
           assertEquals(5, result);
       }
   }
   
  1. 常用注解
   @Test: 标记一个方法为测试方法。
   @BeforeEach: 每个测试方法之前运行。
   @AfterEach: 每个测试方法之后运行。
   @BeforeAll: 在所有测试方法之前运行,仅运行一次。
   @AfterAll: 在所有测试方法之后运行,仅运行一次。

Junit 和Junit5 区别

架构和模块化
  • JUnit 4:
    • 单一 jar 文件。
    • 所有功能都集中在一个库中。
  • JUnit 5:
    • 模块化设计,由三个子项目组成:
      • JUnit Platform: 提供运行测试的基础设施。
      • JUnit Jupiter: 提供新的测试编写和扩展模型。
      • JUnit Vintage: 提供运行 JUnit 3 和 JUnit 4 测试的支持。
注解
  • JUnit 4:
    • @Test: 标记测试方法。
    • @Before: 每个测试方法之前运行。
    • @After: 每个测试方法之后运行。
    • @BeforeClass: 在所有测试方法之前运行,仅运行一次。
    • @AfterClass: 在所有测试方法之后运行,仅运行一次。
    • @Ignore: 忽略测试方法。
  • JUnit 5:
    • @Test: 标记测试方法。
    • @BeforeEach: 每个测试方法之前运行。
    • @AfterEach: 每个测试方法之后运行。
    • @BeforeAll: 在所有测试方法之前运行,仅运行一次。
    • @AfterAll: 在所有测试方法之后运行,仅运行一次。
    • @Disabled: 忽略测试方法或测试类。
    • @Nested: 用于表示嵌套的测试类。
    • @Tag: 用于标记测试以便进行分组和过滤。
    • @DisplayName: 为测试方法提供自定义名称。
断言
  • JUnit 4:
    • 使用 org.junit.Assert 类中的静态方法,例如 assertEqualsassertTrue 等。
  • JUnit 5:
    • 使用 org.junit.jupiter.api.Assertions 类中的静态方法,增加了一些新的断言方法和功能,例如 assertAllassertThrows 等。
条件测试执行
  • JUnit 4:
    • 通过第三方库(如 Assume)实现条件测试执行。
  • JUnit 5:
    • 内置条件执行注解,如 @EnabledOnOs@DisabledOnOs@EnabledOnJre@DisabledOnJre@EnabledIf@DisabledIf 等。
动态测试
  • JUnit 4:
    • 不支持动态测试。
  • JUnit 5:
    • 使用 @TestFactoryDynamicTest 提供对动态测试的支持,可以在运行时生成测试用例。
参数化测试
  • JUnit 4:
    • 使用 @RunWith(Parameterized.class) 和其他注解来实现参数化测试。
  • JUnit 5:
    • 使用 @ParameterizedTest 注解,并结合多个源注解(如 @ValueSource@MethodSource@CsvSource 等)来实现更灵活和强大的参数化测试。
扩展模型
  • JUnit 4:
    • 通过 @RunWithTestRule 扩展功能。
  • JUnit 5:
    • 提供了一个强大的扩展模型,通过实现 Extension 接口,可以更灵活地创建和使用扩展。
向后兼容性
  • JUnit 4:
    • 没有向后兼容性问题,因为是单一框架。
  • JUnit 5:
    • 提供了 JUnit Vintage 引擎,允许在 JUnit 5 平台上运行 JUnit 3 和 JUnit 4 的测试,以便逐步迁移到 JUnit 5。

依赖包说明

Junit maven 包
Junit jupiter dependency

JUnit Jupiter API:提供了编写测试所需的所有注解和类,如 @Test, @BeforeEach, @AfterEach 等。

JUnit Jupiter Engine:用于执行基于 JUnit Jupiter 的测试。这个引擎在添加 junit-jupiter 依赖时自动包含。

所以引入下面的就可以

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
</dependency>

Spring Test

spring-test 是 Spring Framework 提供的一个模块,旨在简化 Spring 应用程序的测试。它为测试 Spring 应用程序中的组件和集成提供了支持,特别是在使用 Spring 的上下文和依赖注入时。spring-test 模块提供了一些重要的功能和工具,帮助开发人员更容易地编写和执行测试。

  1. 引入依赖包
<dependencies>
    <!-- Spring Context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.22</version>
    </dependency>
    <!-- Spring Test -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.22</version>
        <scope>test</scope>
    </dependency>
    <!-- JUnit Jupiter -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.3</version>
        <scope>test</scope>
    </dependency>
    <!-- Mockito -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>4.11.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

  1. 编写测试代码
   import org.junit.jupiter.api.Test;
   import org.junit.jupiter.api.extension.ExtendWith;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.test.context.ContextConfiguration;
   import org.mockito.junit.jupiter.MockitoExtension;
   import org.springframework.test.context.junit.jupiter.SpringExtension;
   
   import static org.junit.jupiter.api.Assertions.*;
   
   // 扩展JUnit 5以支持Spring
   @ExtendWith(SpringExtension.class)
   // 使用mock对象
   @ExtendWith(MockitoExtension.class)
   // 指定Spring配置类或XML配置文件
   @ContextConfiguration(classes = AppConfig.class)
   public class MyServiceTest {
   
       @Autowired
       private MyService myService;
   
       @Test
       public void testService() {
           String result = myService.performAction();
           assertEquals("expectedResult", result);
       }
   }
   

或者

   import org.junit.jupiter.api.Test;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
   
   import static org.junit.jupiter.api.Assertions.*;
   
   @SpringJUnitConfig(AppConfig.class)
   public class MyServiceTest {
   
       @Autowired
       private MyService myService;
   
       @Test
       public void testService() {
           String result = myService.performAction();
           assertEquals("expectedResult", result);
       }
   }

或者 Test SpringMVC

    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit.jupiter.SpringExtension;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = MyControllerTest.WebConfig.class)
    public class MyControllerTest {
    
        @Autowired
        private WebApplicationContext wac;
    
        private MockMvc mockMvc;
    
        @Configuration
        @EnableWebMvc
        static class WebConfig {
    
            @Bean
            public MyController myController() {
                return new MyController();
            }
        }
    
        @BeforeEach
        public void setup() {
            mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        }
    
        @Test
        public void testGetEndpoint() throws Exception {
            mockMvc.perform(get("/my-endpoint"))
                   .andExpect(status().isOk())
                   .andExpect(content().string("expectedResponse"));
        }
    }
    

@SpringJUnitConfig@ExtendWith(SpringExtension.class) 都是用于在 JUnit 5 中整合 Spring Test 框架的注解。它们有着相似的作用,但使用方式略有不同。

@ExtendWith(SpringExtension.class)

@ExtendWith(SpringExtension.class) 是 JUnit 5 提供的一种扩展机制,用于扩展测试的行为。SpringExtension 是 Spring Test 提供的一个扩展,用于在 JUnit 5 测试中启用 Spring Test 上下文。

使用 @ExtendWith(SpringExtension.class) 时,您通常需要另外添加 @ContextConfiguration 或其他 Spring 的配置注解来指定配置类或配置文件。

@SpringJUnitConfig

@SpringJUnitConfig 是一个复合注解,它结合了 @ExtendWith(SpringExtension.class)@ContextConfiguration,使得配置更加简洁。这意味着使用 @SpringJUnitConfig 不需要额外添加 @ContextConfiguration 注解,因为它已经包含了这一功能。

如果您只是进行基本的 Spring 测试,不需要其他额外的扩展,使用 @SpringJUnitConfig 会更加简洁和方便。

如果您的测试类中需要使用多个 JUnit 5 扩展(如 Mockito 等),使用 @ExtendWith(SpringExtension.class) 会更加灵活。

@ContextConfiguration 注解用于在 Spring 测试中指定 Spring 应用上下文的配置。通过这个注解,您可以告诉 Spring 在测试运行时加载哪些配置类或配置文件,从而初始化 Spring 应用上下文。

主要用途

  • 指定配置类:通过 classes 属性,您可以指定一个或多个 Java 配置类。
  • 指定配置文件:通过 locations 属性,您可以指定一个或多个 XML 配置文件的位置。
  • 继承上下文配置:在继承测试类时,可以通过 @ContextConfiguration 实现配置的继承和覆盖。

属性

  • classes:用于指定一个或多个配置类。
  • locations:用于指定一个或多个 XML 配置文件的路径。
  • initializers:用于指定一个或多个 ApplicationContextInitializer 实现类,可以在应用上下文刷新之前对其进行初始化。
  • inheritLocations:指定是否从超类继承 @ContextConfigurationlocations 属性,默认为 true
  • inheritInitializers:指定是否从超类继承 @ContextConfigurationinitializers 属性,默认为 true
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

// 基类测试
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = BaseConfig.class)
public class BaseTest {

    @Autowired
    protected MyBaseService myBaseService;
}

// 子类测试,继承上下文配置
@ContextConfiguration(classes = {BaseConfig.class, ChildConfig.class}, inheritLocations = true)
public class ChildTest extends BaseTest {

    @Autowired
    private MyChildService myChildService;

    @Test
    public void testChildService() {
        assertNotNull(myBaseService);
        assertNotNull(myChildService);
    }
}

Spring-boot Test

  1. 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>3.3.0</version>
    <scope>test</scope>
</dependency>

这个依赖项会自动引入必要的库来支持 Spring Boot 测试,包括 JUnit 5


image
  1. 编写测试类
   import org.junit.jupiter.api.Test;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.boot.test.context.SpringBootTest;
   import static org.assertj.core.api.Assertions.assertThat;
   
    // @RunWith(SpringRunner.class)是Junit4提供的注解,将Spring和Junit链接了起来。
    //假如使用Junit5,不再需要使用@RunWith注解,
    //@SpringBootTest和其它@*Test默认已经包含了该注解。
   @SpringBootTest
   public class MyServiceIntegrationTest {
   
       @Autowired
       private MyService myService;
   
       @Test
       public void testPerformAction() {
           String result = myService.performAction();
           assertThat(result).isEqualTo("expectedResult");
       }
   }

或者,mvcTest

   import org.junit.jupiter.api.Test;
   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.web.servlet.MockMvc;
   import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
   import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
   import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
   import static org.mockito.BDDMockito.given;
   
   @WebMvcTest(MyController.class)
   public class MyControllerTest {
   
       @Autowired
       private MockMvc mockMvc;
   
       @MockBean
       private MyService myService;
   
       @Test
       public void testGetEndpoint() throws Exception {
           given(myService.performAction()).willReturn("expectedResult");
   
           mockMvc.perform(get("/my-endpoint"))
                   .andExpect(status().isOk())
                   .andExpect(content().string("expectedResult"));
       }
   }
   

或者jpa test

   import org.junit.jupiter.api.Test;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
   import static org.assertj.core.api.Assertions.assertThat;
   
   @DataJpaTest
   public class MyRepositoryTest {
   
       @Autowired
       private MyRepository myRepository;
   
       @Test
       public void testFindById() {
           MyEntity entity = new MyEntity();
           entity.setName("TestName");
           myRepository.save(entity);
   
           MyEntity found = myRepository.findById(entity.getId()).orElse(null);
           assertThat(found).isNotNull();
           assertThat(found.getName()).isEqualTo("TestName");
       }
   }
   

@SpringBootTest:用于加载整个 Spring 应用上下文进行集成测试。适用于需要测试多个组件协作的场景。

@WebMvcTest:用于加载 Web 层组件(如控制器)进行测试,不加载整个应用上下文。适用于测试控制器及其相关的过滤器、拦截器等。

@DataJpaTest:用于测试 JPA 持久层组件。它会自动配置嵌入式数据库(如 H2),并对持久层进行测试。

使用@SpringBootTest时并没有像@ContextConfiguration一样显示指定locations或classes属性,原因在于@SpringBootTest注解会自动检索程序的配置文件,检索顺序是从当前包开始,逐级向上查找被@SpringBootApplication或@SpringBootConfiguration注解的类。

相关文章

网友评论

      本文标题:Junit Test(从junit -> spring-test

      本文链接:https://www.haomeiwen.com/subject/feaucjtx.html