Tom*_*rio 5 mockito kotlin spring-boot spring-webflux
我正在开发一个简单的项目,该项目使用 Spring Boot 2 和 Spring WebFlux 使用 Kotlin。我为我的处理函数编写了测试(其中我使用 Mockito 模拟依赖项)。
但是,我的路由函数似乎没有触发处理程序,因为我的所有请求都会返回HTTP 404 NOT FOUND(即使路由是正确的)。
我查看了各种其他项目,以找出这些测试应该如何编写(此处,此处),但问题仍然存在。
代码如下(也可以在GitHub上找到):
用户路由器测试
@ExtendWith(SpringExtension::class, MockitoExtension::class)
@Import(UserHandler::class)
@WebFluxTest
class UserRouterTest {
@MockBean
private lateinit var userService: UserService
@Autowired
private lateinit var userHandler: UserHandler
@Test
fun givenExistingCustomer_whenGetCustomerByID_thenCustomerFound() {
val expectedCustomer = User("test", "test")
val id = expectedCustomer.userID
`when`(userService.getUserByID(id)).thenReturn(Optional.ofNullable(expectedCustomer))
val router = UserRouter().userRoutes(userHandler)
val client = WebTestClient.bindToRouterFunction(router).build()
client.get()
.uri("/users/$id")
.accept(MediaType.ALL)
.exchange()
.expectStatus().isOk
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.expectBody(User::class.java)
}
}
Run Code Online (Sandbox Code Playgroud)
用户
@Entity
class User(var username : String, var password: String) {
@Id
val userID = UUID.randomUUID()
}
Run Code Online (Sandbox Code Playgroud)
用户存储库
@Repository
interface UserRepository : JpaRepository<User, UUID>{
}
Run Code Online (Sandbox Code Playgroud)
用户服务
@Service
class UserService(
private val userRepository: UserRepository
) {
fun getUserByID(id: UUID): Optional<User> {
return Optional.of(
try {
userRepository.getOne(id)
} catch (e: EntityNotFoundException) {
User("test", "test")
}
)
}
fun addUser(user: User) {
userRepository.save(user)
}
}
Run Code Online (Sandbox Code Playgroud)
用户处理程序
@Component
class UserHandler(
private val userService: UserService
) {
fun getUserWithID(request: ServerRequest): Mono<ServerResponse> {
val id = try {
UUID.fromString(request.pathVariable("userID"))
} catch (e: IllegalArgumentException) {
return ServerResponse.badRequest().syncBody("Invalid user id")
}
val user = userService.getUserByID(id).get()
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(user))
}
}
Run Code Online (Sandbox Code Playgroud)
用户路由器
@Configuration
class UserRouter {
@Bean
fun userRoutes(userHandler: UserHandler) = router {
contentType(MediaType.APPLICATION_JSON_UTF8).nest {
GET("/users/{userID}", userHandler::getUserWithID)
GET("") { ServerResponse.ok().build() }
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
要根据一个或多个查询参数(无论其值是多少)的存在进行路由,我们可以执行以下操作: UserRouter
@Configuration
class UserRouter {
@Bean
fun userRoutes(userHandler: UserHandler) = router {
GET("/users/{userID}", userHandler::getUserWithID)
(GET("/users/")
and queryParam("username") { true }
and queryParam("password") { true }
)
.invoke(userHandler::getUsers)
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这GET("/users/?username={username}", userHandler::getUsersWithUsername)不起作用。
对于所有面临相同问题但注意到您的问题不涉及不contentType匹配的人,我建议检查您的依赖项(build.gradle、pom.xml 等)。
就我而言,当我定义了以下两个依赖项时,我遇到了同样的问题:
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
Run Code Online (Sandbox Code Playgroud)
如果您使用函数式风格来声明端点(使用RouterFunction),那么同时拥有这两个依赖项可能会导致问题。
要解决此问题,您应该删除其中一个依赖项。如果您正在使用spring-webflux,请确保在构建配置中仅保留以下内容:
implementation 'org.springframework.boot:spring-boot-starter-webflux'
Run Code Online (Sandbox Code Playgroud)
注意:值得注意的是,从 开始spring-boot 3.1.0,当两个依赖项都存在时,不会出现警告或错误。您只会收到404 Not Found回复,而不会进一步表明问题。
您可以在 spring.io 指南中找到一个可用的小应用程序
小智 4
路由器的配置方式 - contentType(MediaType.APPLICATION_JSON_UTF8).nest- 将仅匹配具有此内容类型的请求,因此您必须删除 contentType 先决条件或更改测试以包含它
client.get()
.uri("/users/$id")
.accept(MediaType.ALL)
.header("Content-Type", "application/json;charset=UTF-8")
.exchange()
.expectStatus().isOk
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.expectBody(User::class.java)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7899 次 |
| 最近记录: |