知識庫 / Spring / Spring MVC RSS 訂閱

Spring MockMvc 支持的 REST-assured 插件

REST,Spring MVC,Testing
HongKong
11
03:51 AM · Dec 06 ,2025

1. 介紹

在本教程中,我們將學習如何使用 RestAssuredMockMvc 測試我們的 Spring REST 控制器。 RestAssuredMockMvc 是基於 Spring 的 MockMvc 構建的 REST-assured API。

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

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

2. Maven 依賴

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

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

3. 初始化 RestAssuredMockMvc

接下來,我們需要初始化 RestAssuredMockMvc,這是 DSL 的起點,無論是在 獨立模式還是 Web 應用程序上下文模式下。

在兩種模式下,我們可以隨時隨地執行它,也可以靜態地一次性配置。讓我們來看一些示例。

3.1. 獨立模式

在獨立模式下,我們使用 RestAssuredMockMvc,並使用一個或多個 @Controller@ControllerAdvice 註解的類。

如果只有少量測試,我們可以隨時初始化 RestAssuredMockMvc

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

不過,如果測試數量很多,直接進行一次靜態分析會更容易:

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

3.2. Web Application Context

在 Web Application Context 模式下,我們使用 RestAssuredMockMvc 實例初始化 WebApplicationContext</em/>。

類似於我們在 standalone 模式下進行的設置,我們可以隨時在每個測試中初始化 RestAssuredMockMvc</em/>。

@Autowired
private WebApplicationContext webApplicationContext;

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

或者,我們也可以靜態地一次性完成它:

@Autowired
private WebApplicationContext webApplicationContext;

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

4. 系統測試對象 (SUT)

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

@SpringBootApplication
class Application {

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

接下來,我們有一個簡單的 <em><a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html">@RestController</a></em>,它暴露了我們的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-assured 進行 REST Controller 單元測試

我們可以使用 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("[]")));
}

初始化 RestAssuredMockMvc</em/>,同時結合我們的 @ControllerAdvice</em/> 和 @RestController</em/>,使我們能夠測試我們的異常場景:

@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() — 指定 HTTP 請求的詳細信息
  • when() — 指定 HTTP 動詞以及路由
  • then() — 驗證 HTTP 響應

6. 使用 REST-assured 進行 REST Controller 集成測試

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

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

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

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

接下來,我們注入 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 的 <em>spring-mock-mvc</em> 模塊。

使用 <em>RestAssuredMockMvc</em><strong>獨立模式</strong>下進行單元測試非常方便,因為它只會初始化提供的Controller`,從而保持測試速度。

使用 <em>RestAssuredMockMvc</em><strong>Web 應用程序上下文模式</strong>下進行集成測試,因為它可以利用完整的WebApplicationContext`。

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

發佈 評論

Some HTML is okay.