[英]Endpoint testing with Spring Boot and JUnit 5
感觉很愚蠢,但我无法在 Spring Boot(版本2.7.1
)和 JUnit 5 中测试端点。
简而言之,我想测试真正的端点响应,所以我创建了一个测试 class,如测试 Web 层中所述。 这里的代码:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApiDocumentationControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void getOpenApiDocumentationShouldReturnOk() {
assertThat(restTemplate.getForEntity("/api-docs", String.class).getStatusCode())
.isEqualTo(HttpStatus.OK);
}
}
但是当我运行测试时, TestRestTemplate
调用http://localhost:8080/api-docs
忽略了服务器应该监听随机端口的事实。
我错过了什么? 正如其他示例所暗示的那样,我尝试添加:
@LocalServerPort
private int randomServerPort;
但在这种情况下,我在测试启动期间出现异常:
java.lang.IllegalArgumentException: Could not resolve placeholder 'local.server.port' in value "${local.server.port}"
我尝试将0
设置为端口——框架应将其视为随机端口——但没有成功。 Spring 抱怨它无法收听localhost:0
。
服务配置为空(AKA application.yaml
为空,我没有通过其他方式设置params),所以所有的配置值都是Spring的默认值。
可能这对傻瓜来说是个问题,但从昨天开始我一直在寻找解决方案,但我没有找到。
@Slf4j
@Controller
public class ApiDocumentationController {
private final Resource resourceFile;
private final ObjectMapper yamlReader;
private final ObjectMapper jsonWriter;
public ApiDocumentationController(@Value("classpath:openapi/api-documentation.yaml") Resource resourceFile,
@Qualifier("yamlReader") ObjectMapper yamlReader,
ObjectMapper objectMapper) {
this.resourceFile = resourceFile;
this.yamlReader = yamlReader;
this.jsonWriter = objectMapper;
}
@GetMapping(value = "/api-docs", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getOpenApiDocumentation() {
return Try.of(() -> yamlReader.readValue(resourceFile.getInputStream(), Object.class))
.mapTry(jsonWriter::writeValueAsString)
.map(apiDocumentation -> ResponseEntity.status(HttpStatus.OK).body(apiDocumentation))
.get(); // FIXME This forced Try::get is ugly
}
}
@SpringBootApplication
public class AirportTravellersInsightsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AirportTravellersInsightsServiceApplication.class, args);
}
(这是build.gradle
的摘录。)
上面提到的测试在integrationTest
测试源集中。
plugins {
id 'org.springframework.boot' version '2.7.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'jacoco'
id 'checkstyle'
id 'idea'
}
group = 'example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
ext.versions = [
checkstyleVersion: "8.39",
vavrVersion: "0.10.4"
]
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation "io.vavr:vavr:${versions.vavrVersion}"
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'
// TEST
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine"
testAnnotationProcessor 'org.projectlombok:lombok'
}
sourceSets {
integrationTest {
compileClasspath += sourceSets.main.output
compileClasspath += sourceSets.test.output
runtimeClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.test.output
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
integrationTestImplementation.extendsFrom testImplementation
integrationTestRuntimeOnly.extendsFrom runtimeOnly
implementation {
exclude module: 'spring-boot-starter-tomcat'
}
}
tasks.named('test') {
useJUnitPlatform()
}
task integrationTest(type: Test, description: 'Runs integration tests.', group: LifecycleBasePlugin.VERIFICATION_GROUP) {
useJUnitPlatform()
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
shouldRunAfter test
}
check.dependsOn integrationTest
我建议您使用org.springframework.test.web.servlet.MockMvc
来测试您的端点。 您可以阅读本文以了解为什么应该使用MockMvc
。
MockMvc 提供对 Spring MVC 测试的支持。 它封装了所有 web 个应用程序 bean 并使它们可用于测试。
您可以这样执行测试:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class ApiDocumentationControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void getOpenApiDocumentationShouldReturnOk() {
// Act
ResultActions response = mockMvc.perform(//
get("/api-docs"));
// Assert
response.andDo(print()).//
andExpect(status().isOk())//
}
}
更新
还有另一种方法可以在您的测试 class 中启动MockMvc
实例:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApiDocumentationControllerIntegrationTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.