【Springboot】单元测试Junit5应用

JUnit 5是一个功能强大的测试框架,常用于编写和执行这些单元测试。以下是一些JUnit 5中的常用注解、断言、前置条件、嵌套测试和参数化测试的例子:

1.环境启动

@SpringBootTest 注解:

classes = SmartApplication.class:这个属性指定了一个或多个Spring Boot应用程序的启动类(入口点)。在测试中使用启动类可以让Spring Boot应用程序的上下文被加载,以便进行测试。

webEnvironment属性:

  • NONE: 不启动任何Web相关的环境,通常用于不需要Web环境的测试。
  • RANDOM_PORT: 随机分配一个端口来启动Web环境。
  • ANY: 使用第一个可用端口来启动Web环境。
  • MOCK: 使用MockMvc来模拟Web环境,而不用启动真实的Web服务器。
  • DEFINED_PORT: 使用在@LocalServerPort或@Value注解中定义的端口来启动Web环境。使用配置文件中定义好的端口
    @SpringBootTest(classes = SmartApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    class JunitApplicationTests {@Autowired
    	TestService testService;
    	@Test
    	void contextLoads() {System.err.println("测试启动");
    		System.out.println(testService.test());
    	}
    }
    

    2. 常用注解

    • @Test:用于标记一个方法作为测试方法。
    • @BeforeEach:在每个测试方法之前执行一次。
    • @AfterEach:在每个测试方法之后执行一次。
    • @BeforeAll:在所有测试方法之前执行一次。
    • @AfterAll:在所有测试方法之后执行一次。
      import org.junit.jupiter.api.BeforeEach;
      import org.junit.jupiter.api.AfterEach;
      import org.junit.jupiter.api.BeforeAll;
      import org.junit.jupiter.api.AfterAll;
      import org.junit.jupiter.api.Test;
      public class MyServiceTest { private MyService service;
          @BeforeAll
          public static void setup() { // 在所有测试之前执行的代码
          }
          @BeforeEach
          public void setupEachTest() { // 在每个测试之前执行的代码
              service = new MyService();
          }
          @AfterEach
          public void teardown() { // 在每个测试之后执行的代码
          }
          @AfterAll
          public static void teardown() { // 在所有测试之后执行的代码
          }
          @Test
          public void myTestMethod() { // 测试逻辑
          }
      }
      

      3.模拟发送HTTP请求

      断言

      • Assertions.assertEquals(expected, actual):断言期望值与实际值相等。
      • Assertions.assertNotEquals(unexpected, actual):断言期望值与实际值不等。
      • Assertions.assertNull(object):断言对象为null。
      • Assertions.assertNotNull(object):断言对象不为null。
      • Assertions.assertTrue(condition):断言条件为true。
      • Assertions.assertFalse(condition):断言条件为false。

        使用RestTemplate发送请求

        @ExtendWith(SpringExtension.class)
        @ContextConfiguration(classes = YourApplication.class)
        public class YourControllerTest { @Autowired
            private RestTemplate restTemplate;
            @Test
            public void should_handle_request_correctly() { // 模拟请求
                String url = "http://example.com/api";
                HttpEntity request = new HttpEntity<>("some request body", headers);
                
                // 发送请求
                ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
                
                // 断言
                assertEquals(HttpStatus.OK, response.getStatusCode());
                assertEquals("expected response body", response.getBody());
            }
        }
        

        使用Mock发送请求

        import static org.junit.jupiter.api.Assertions.assertEquals;
        import static org.mockito.Mockito.when;
        import java.util.HashMap;
        import java.util.Map;
        import org.junit.jupiter.api.Test;
        import org.junit.jupiter.api.extension.ExtendWith;
        import org.mockito.Mock;
        import org.mockito.junit.jupiter.MockitoExtension;
        import org.springframework.boot.test.context.SpringBootTest;
        import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
        import org.springframework.http.MediaType;
        import org.springframework.test.web.servlet.MockMvc;
        import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
        import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
        import org.springframework.test.web.servlet.setup.MockMvcBuilders;
        import com.example.yourproject.controller.YourController;
        @ExtendWith(MockitoExtension.class)
        @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
        public class YourControllerTest { @Mock
            private YourController yourController;
            private MockMvc mockMvc;
            @BeforeEach
            public void setUp() { mockMvc = MockMvcBuilders.standaloneSetup(yourController).build();
            }
            @Test
            public void testYourController() throws Exception { // 准备请求参数
                Map requestParams = new HashMap<>();
                requestParams.put("param1", "value1");
                requestParams.put("param2", "value2");
                // 设置模拟的响应
                String expectedResponse = "{\"message\":\"Hello World!\"}";
                when(yourController.yourMethod(requestParams)).thenReturn(expectedResponse);
                // 发送请求并验证结果
                mockMvc.perform(MockMvcRequestBuilders.post("/your-endpoint")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(JSON.toJSONString(requestParams)))
                        .andExpect(MockMvcResultMatchers.status().isOk())
                        .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_VALUE))
                        .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Hello World!"));
            }
        }