整合測試

情境

  1. 設定測試環境
  2. 使用 Spring Boot 的話,可以使用 @SpringBootTest 註解來啟動整個應用程式上下文。
  3. 使用內存資料庫如 H2 來進行測試,避免對實際資料庫的依賴。

  4. 模擬依賴項

  5. 使用 @MockBean@Mock 來模擬依賴的服務或元件,確保測試的獨立性。

  6. 撰寫測試案例

  7. 使用 MockMvc 來模擬 HTTP 請求,測試 RESTful API。
  8. 使用 @Sql 註解來載入測試資料。

  9. 執行測試

  10. 使用 JUnit 或 TestNG 來執行測試案例。
  11. 使用 @DirtiesContext 註解來確保每個測試方法執行前後的上下文清理。

以下是一個簡單的範例,展示如何使用 Spring Boot 和 MockMvc 進行整合測試:

@SpringBootTest
@AutoConfigureMockMvc
@Sql(scripts = "classpath:test/data.sql")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class TestToDoController {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private TodoService todoService;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void testGetTodos() throws Exception {
        String returnString = mockMvc.perform(MockMvcRequestBuilders.get("/api/todos")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);

        List<Todo> actualList = objectMapper.readValue(returnString, new TypeReference<List<Todo>>() {});
        // 進行斷言
        assertEquals(1, actualList.size());
    }
}

輸出結果

为了将 JSON 请求和结果依情境输出,可以在参数化测试中使用类似之前提到的 JsonExporter 工具类。以下是一个示例,展示如何在参数化测试中导出 JSON 请求和响应,并按情境进行整理。

示例代码

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.io.File;
import java.io.IOException;
import java.time.Month;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

public class AllowCustomerCheckServiceTest {

    @InjectMocks
    private AllowCustomerCheckService allowCustomerCheckService;

    @Mock
    private AllowanceSettingViewRepository allowanceSettingViewRepository;

    @Mock
    private AllowanceTrxLineRepository allowanceTrxLineRepository;

    @Mock
    private CommonServiceClient commonServiceClient;

    @Mock
    private AuthServiceClient authServiceClient;

    @Mock
    private DplRuleRepository dplRuleRepository;

    private ObjectMapper objectMapper;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
        objectMapper = new ObjectMapper();
    }

    @ParameterizedTest(name = "{index} {0} is 30 days long")
    @EnumSource(value = Month.class, names = {"APRIL", "JUNE", "SEPTEMBER", "NOVEMBER"})
    void someMonths_Are30DaysLong(Month month) throws IOException {
        final boolean isALeapYear = false;
        assertEquals(30, month.length(isALeapYear));

        // 创建请求对象
        AllowCustomerCheckRequest request = createRequestForMonth(month);

        // 模拟依赖行为
        when(allowanceSettingViewRepository.getAllowCustomerCheckSetting(any())).thenReturn(new HashMap<>());

        // 调用方法
        AllowCustomerResponse response = allowCustomerCheckService.allowItemCheck(request);

        // 导出请求和响应
        String scenario = month.name().toLowerCase();
        JsonExporter.exportJson("output/" + scenario, "request.json", request);
        JsonExporter.exportJson("output/" + scenario, "response.json", response);
    }

    private AllowCustomerCheckRequest createRequestForMonth(Month month) {
        // 根据月份创建不同的请求对象
        AllowCustomerCheckRequest request = new AllowCustomerCheckRequest();
        request.setOuCode("OU123");
        request.setTrxReferenceNo("TRX123");
        request.setIsBlackCustomerCheck(false);
        // 添加其他必要的字段和数据
        return request;
    }
}

JsonExporter 工具类

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.io.IOException;

public class JsonExporter {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static void exportJson(String directory, String fileName, Object data) throws IOException {
        File dir = new File(directory);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir, fileName);
        objectMapper.writerWithDefaultPrettyPrinter().writeValue(file, data);
    }
}

解释

  1. 参数化测试:使用 @ParameterizedTest@EnumSource 注解来测试不同的月份。
  2. 创建请求对象:在 createRequestForMonth 方法中,根据不同的月份创建请求对象。
  3. 模拟依赖行为:使用 Mockito 模拟依赖行为。
  4. 调用方法:调用 allowItemCheck 方法并获取响应。
  5. 导出请求和响应:使用 JsonExporter 工具类将请求和响应导出到文件中,并按情境(月份)进行整理。

这样,你就可以在参数化测试中将 JSON 请求和结果依情境输出并整理。