Spring MockMvc 支持的 REST-assured 增強

REST,Spring MVC,Testing
Remote
0
09:38 AM · Dec 01 ,2025

1. 簡介

在本教程中,我們將學習如何使用 RestAssuredMockMvc 測試我們的 Spring REST 控制器,這是一個建立在 Spring MockMvc 之上的 REST-assured API。

首先,我們將研究不同的設置選項。然後,我們將深入瞭解如何編寫單元測試和集成測試。

本教程使用 Spring MVC、Spring MockMVC 和 REST-assured,因此請務必查看這些教程。

2. Maven 依賴

在我們開始編寫測試之前,我們需要將 io.rest-assured:spring-mock-mvc 模塊 導入到我們的 Maven pom.xml 中:

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>spring-mock-mvc</artifactId>
    <version>3.3.0</version>
    <scope>test</scope>
</dependency>

3. 初始 RestAssuredMockMvc

接下來,我們需要初始化 RestAssuredMockMvc,這是 DSL 的起點,可以是 standaloneweb 應用程序上下文 模式。

在兩種模式下,我們可以隨時隨地(per test)進行初始化,也可以靜態地一次性進行。讓我們來看一些示例。

3.1. 獨立模式

在獨立模式下,我們 使用一個或多個 @Controller@ControllerAdvice 類型的類來初始化 RestAssuredMockMvc

如果只有幾個測試,我們可以隨時隨地(per test)初始化 RestAssuredMockMvc

@Test
public void whenGetCourse() {
    given()
      .standaloneSetup(new CourseController())
      //...
}

但是,如果有很多測試,那麼一次性靜態地進行會更容易:

@Before
public void initialiseRestAssuredMockMvcStandalone() {
    RestAssuredMockMvc.standaloneSetup(new CourseController());
}

3.2. Web 應用程序上下文

在 web 應用程序上下文模式下,我們 使用 Spring 的 WebApplicationContext 實例來初始化 RestAssuredMockMvc

類似於獨立模式的設置,我們可以在每個測試中隨時隨地(per test)初始化 RestAssuredMockMvc

@Autowired
private WebApplicationContext webApplicationContext;

@Test
public void whenGetCourse() {
    given()
      .webAppContextSetup(webApplicationContext)
      //...
}

或者,再次,我們可以一次性靜態地進行:

@Autowired
private WebApplicationContext webApplicationContext;

@Before
public void initialiseRestAssuredMockMvcWebApplicationContext() {
    RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
}

4. System Under Test (SUT)

在我們開始查看一些示例測試之前,我們需要一個測試對象。讓我們查看我們的系統下測試,從我們的 @SpringBootApplication 配置開始:

@SpringBootApplication
class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

接下來,我們有一個簡單的 @RestController,暴露我們的 Course 領域:

@RestController
@RequestMapping(path = "/courses")
public class CourseController {

    private final CourseService courseService;

    public CourseController(CourseService courseService) {
        this.courseService = courseService;
    }

    @GetMapping(produces = APPLICATION_JSON_UTF8_VALUE)
    public Collection<Course> getCourses() {
        return courseService.getCourses();
    }

    @GetMapping(path = "/{code}", produces = APPLICATION_JSON_UTF8_VALUE)
    public Course getCourse(@PathVariable String code) {
        return courseService.getCourse(code);
    }
}
class Course {

    private String code;
    
    // usual contructors, getters and setters
}

最後,我們的服務類和 @ControllerAdvice,用於處理我們的 CourseNotFoundException:

@Service
class CourseService {

    private static final Map<String, Course> COURSE_MAP = new ConcurrentHashMap<>();

    static {
        Course wizardry = new Course("Wizardry");
        COURSE_MAP.put(wizardry.getCode(), wizardry);
    }

    Collection<Course> getCourses() {
        return COURSE_MAP.values();
    }

    Course getCourse(String code) {
        return Optional.ofNullable(COURSE_MAP.get(code)).orElseThrow(() -> 
          new CourseNotFoundException(code));
    }
}
@ControllerAdvice(assignableTypes = CourseController.class)
public class CourseControllerExceptionHandler extends ResponseEntityExceptionHandler {

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(CourseNotFoundException.class)
    public void handleCourseNotFoundException(CourseNotFoundException cnfe) {
        //...
    }
}
class CourseNotFoundException extends RuntimeException {

    CourseNotFoundException(String code) {
        super(code);
    }
}

現在我們有了測試對象,讓我們查看一些 RestAssuredMockMvc 測試。

5. REST 控制器單元測試與 REST-assured

我們可以使用 RestAssuredMockMvc 與我們最喜歡的測試工具 JUnit 和 Mockito 一起測試我們的 @RestController

首先,我們 mock 並構造 SUT,然後像下面這樣以獨立模式初始化 RestAssuredMockMvc

@RunWith(MockitoJUnitRunner.class)
public class CourseControllerUnitTest {

    @Mock
    private CourseService courseService;
    @InjectMocks
    private CourseController courseController;
    @InjectMocks
    private CourseControllerExceptionHandler courseControllerExceptionHandler;

    @Before
    public void initialiseRestAssuredMockMvcStandalone() {
        RestAssuredMockMvc.standaloneSetup(courseController, courseControllerExceptionHandler);
    }
}

因為我們在 @Before 方法中靜態地初始化了 RestAssuredMockMvc,所以不需要在每個測試中初始化它。

獨立模式非常適合單元測試,因為它只初始化我們提供的控制器,而不是整個應用程序上下文。這使得我們的測試速度更快。

現在,讓我們看看一個示例測試:

@Test
public void givenNoExistingCoursesWhenGetCoursesThenRespondWithStatusOkAndEmptyArray() {
    when(courseService.getCourses()).thenReturn(Collections.emptyList());

    given()
      .when()
        .get("/courses")
      .then()
        .log().ifValidationFails()
        .statusCode(OK.value())
        .contentType(JSON)
        .body(is(equalTo("[]")));
}

@ControllerAdvice 附加到我們的 @RestController,使我們能夠測試我們的異常場景:

@Test
public void givenNoMatchingCoursesWhenGetCoursesThenRespondWithStatusNotFound() {
    String nonMatchingCourseCode = "nonMatchingCourseCode";

    when(courseService.getCourse(nonMatchingCourseCode)).thenThrow(
      new CourseNotFoundException(nonMatchingCourseCode));

    given()
      .when()
        .get("/courses/" + nonMatchingCourseCode)
      .then()
        .log().ifValidationFails()
        .statusCode(NOT_FOUND.value());
}

如上面所示,REST-assured 使用熟悉的 given-when-then 場景格式來定義測試:

  • given() — 指定 HTTP 請求的詳細信息
  • when() — 指定 HTTP 動詞以及路由
  • then() — 驗證 HTTP 響應

6. REST 控制器集成測試與 REST-assured

我們還可以使用 RestAssuredMockMvc 與 Spring 的測試工具,用於我們的集成測試。

首先,我們設置測試類,使用 @RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = RANDOM_PORT):

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
public class CourseControllerIntegrationTest {
    //...
}

這將使用在我們的 @SpringBootApplication 類中配置的應用程序上下文運行我們的測試,並在隨機端口上運行。

接下來,我們注入我們的 WebApplicationContext 並使用它來初始化 RestAssuredMockMvc,如上所述:

@Autowired
private WebApplicationContext webApplicationContext;

@Before
public void initialiseRestAssuredMockMvcWebApplicationContext() {
    RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
}

現在,我們已經設置了測試類並且 RestAssuredMockMvc 已經初始化,我們準備好開始編寫測試:

@Test
public void givenNoMatchingCourseCodeWhenGetCourseThenRespondWithStatusNotFound() {
    String nonMatchingCourseCode = "nonMatchingCourseCode";

    given()
      .when()
        .get("/courses/" + nonMatchingCourseCode)
      .then()
        .log().ifValidationFails()
        .statusCode(NOT_FOUND.value());
}

請記住,由於我們在 @Before 方法中靜態地初始化了 RestAssuredMockMvc,因此我們不需要在每個測試中初始化它。

要更深入地瞭解 REST-assured API,請查看我們的 REST-assured 指南。

7. 結論

在本教程中,我們看到了如何使用 REST-assured 測試我們的 Spring MVC 應用程序,利用 REST-assured 的 spring-mock-mvc 模塊。

獨立模式 初始化 RestAssuredMockMvc 非常適合單元測試,因為它只初始化提供的 Controller,從而保持測試速度。

Web 應用程序上下文模式 初始化 RestAssuredMockMvc 非常適合集成測試,因為它使用我們的完整 WebApplicationContext

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.