You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Rest调用编写JUnit测试用例?求指导CustController测试

Testing a Spring REST Controller (JUnit for CustController)

Hey there! As someone new to writing JUnit tests for REST endpoints, let's walk through how to test your CustController step by step. We'll use Spring Boot Test (with MockMvc) and Mockito—the standard tools for testing Spring REST controllers without spinning up a full server.

First, Add Required Dependencies

Make sure your pom.xml (Maven) includes these dependencies for testing:

<dependencies>
    <!-- Spring Boot Test Starter -->
    <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>
    <!-- Mockito (included in spring-boot-starter-test, but explicit is okay) -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Key Concepts for Testing REST Controllers

  • MockMvc: Simulates HTTP requests to your controller, so you don't need to start a real server.
  • @WebMvcTest: Loads only the web layer (controllers, filters, etc.) instead of the entire Spring context—fast and focused.
  • @MockBean: Creates mock implementations of your controller's dependencies (like CustService, MarCusService) so you can control their behavior during tests.

Full Test Class for CustController

Here's a complete test class covering all critical scenarios in your methodCall endpoint:

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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(CustController.class)
class CustControllerTest {

    @Autowired
    private MockMvc mockMvc; // Handles simulated HTTP requests

    // Mock all dependencies of CustController
    @MockBean
    private CustService custService;
    @MockBean
    private MarCusService marCustService;
    @MockBean
    private CusValidator validator;
    @MockBean
    private CMSSiteService cmsSiteService;
    @MockBean
    private Config config; // Assuming Config is a bean holding parameters

    // Helper XML for CustDTO (adjust based on your actual DTO structure)
    private static final String VALID_CUST_DTO_XML = """
        <CustDTO>
            <group>USER</group>
            <!-- Add other fields required by your DTO -->
        </CustDTO>
        """;

    private static final String CUST_DTO_ALL_GROUP_XML = """
        <CustDTO>
            <group>ALL</group>
        </CustDTO>
        """;

    @Test
    void methodCall_WhenGroupIsNotAll_AndValidationFails_ReturnsOkWithErrorMessage() throws Exception {
        // Arrange: Make validator throw a WebServicesException
        doThrow(new WebServicesException("Invalid data"))
                .when(validator).validate(any(CustDTO.class));

        // Act & Assert
        mockMvc.perform(put("/cutdata/methodcall")
                        .contentType(MediaType.TEXT_XML)
                        .content(VALID_CUST_DTO_XML))
                .andExpect(status().isOk())
                .andExpect(content().string("Invalid data"));
    }

    @Test
    void methodCall_WhenSiteIsMatching_AndMarCustReturns200_ReturnsCreatedWithMessage() throws Exception {
        // Arrange: Mock current site to match the configured UID
        CMSSiteModel mockSite = mock(CMSSiteModel.class);
        when(mockSite.getUid()).thenReturn("test-site-uid-matching-config");
        when(cmsSiteService.getCurrentSite()).thenReturn(mockSite);
        when(config.getParameter("****.siteuid")).thenReturn("test-site-uid");
        // Mock marCustService to return success status
        when(marCustService.processData(any(CustDTO.class))).thenReturn("200:Data processed successfully");

        // Act & Assert
        mockMvc.perform(put("/cutdata/methodcall")
                        .contentType(MediaType.TEXT_XML)
                        .content(VALID_CUST_DTO_XML))
                .andExpect(status().isCreated())
                .andExpect(content().string("Data processed successfully"));
    }

    @Test
    void methodCall_WhenSiteIsNotMatching_AndCustServiceReturns400_ReturnsBadRequest() throws Exception {
        // Arrange: Mock current site to NOT match the configured UID
        CMSSiteModel mockSite = mock(CMSSiteModel.class);
        when(mockSite.getUid()).thenReturn("test-site-uid-not-matching");
        when(cmsSiteService.getCurrentSite()).thenReturn(mockSite);
        when(config.getParameter("****.siteuid")).thenReturn("test-site-uid");
        // Mock custService to return error status
        when(custService.processData1(any(CustDTO.class))).thenReturn("400:Invalid input");

        // Act & Assert
        mockMvc.perform(put("/cutdata/methodcall")
                        .contentType(MediaType.TEXT_XML)
                        .content(VALID_CUST_DTO_XML))
                .andExpect(status().isBadRequest())
                .andExpect(content().string("Invalid input"));
    }

    @Test
    void methodCall_WhenServiceThrowsException_ReturnsBadRequest() throws Exception {
        // Arrange: Mock site and make service throw exception
        CMSSiteModel mockSite = mock(CMSSiteModel.class);
        when(mockSite.getUid()).thenReturn("test-site-uid");
        when(cmsSiteService.getCurrentSite()).thenReturn(mockSite);
        when(config.getParameter("****.siteuid")).thenReturn("test-site-uid");
        doThrow(new RuntimeException("Unexpected error"))
                .when(marCustService).processData(any(CustDTO.class));

        // Act & Assert
        mockMvc.perform(put("/cutdata/methodcall")
                        .contentType(MediaType.TEXT_XML)
                        .content(VALID_CUST_DTO_XML))
                .andExpect(status().isBadRequest());
    }

    @Test
    void methodCall_WhenGroupIsAll_SkipsValidation() throws Exception {
        // Arrange: Mock site and service success
        CMSSiteModel mockSite = mock(CMSSiteModel.class);
        when(mockSite.getUid()).thenReturn("test-site-uid");
        when(cmsSiteService.getCurrentSite()).thenReturn(mockSite);
        when(config.getParameter("****.siteuid")).thenReturn("test-site-uid");
        when(marCustService.processData(any(CustDTO.class))).thenReturn("200:Success");

        // Act & Assert
        mockMvc.perform(put("/cutdata/methodcall")
                        .contentType(MediaType.TEXT_XML)
                        .content(CUST_DTO_ALL_GROUP_XML))
                .andExpect(status().isCreated())
                .andExpect(content().string("Success"));

        // Verify validator was NOT called (since group is ALL)
        verify(validator, never()).validate(any(CustDTO.class));
    }
}

Explanation of Key Test Scenarios

Let's break down what each test covers:

  • Validation Failure: Ensures that when the validator throws an error, the controller returns an OK status with the error message.
  • Matching Site & Success: Tests the path where the current site matches the configured UID, so marCustService is called, and a success response is returned.
  • Non-Matching Site & Error: Tests the path where the site doesn't match, so custService is called, and a bad request is returned for an error status.
  • Service Exception: Ensures that any unexpected exception from the service results in a bad request.
  • Skip Validation for ALL Group: Verifies that when the group is ALL, the validator is never invoked (as per your controller logic).

Tips for Your Tests

  • XML Request Body: Adjust the XML strings to match your actual CustDTO fields—Spring will automatically deserialize the XML to your DTO if you have JAXB or Jackson XML dependencies set up.
  • Mock Config: If Config isn't a bean, you might need to use ReflectionTestUtils to set the parameter value directly in the controller.
  • Log Verification: If you want to verify that the logger is called on exception, you can use a mocking framework like Mockito to spy on the logger.

内容的提问来源于stack exchange,提问作者Panda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:40:29