Mockito @MockBean在Kotlin上不会执行



我对Kotlin/Mockito问题感到非常沮丧

我想完成的很简单,我在我的springboot应用程序上有一个AuthorizationFilter,为了测试目的,我想模拟它的行为,让测试请求通过

My AuthorizationFilter确实调用了一个API,该API随后将提供用户授权状态。我认为模拟这个最简单的方法是把AuthApi模拟到过滤器中然后返回我想要的任何状态。但它随机工作

@Component
class AuthorizationFilter(
val authApi: authApi
) : OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
if (request.method.equals("OPTIONS")) {
filterChain.doFilter(request, response)
return
}
val token = request.getHeader("authorization")
if (token == null) {
response.sendError(401)
return
}

runCatching {
authApi.authorize(token.replace("Bearer ", ""))
}.onSuccess {
AuthorizationContext.set(it)
filterChain.doFilter(request, response)
}.onFailure {
it.printStackTrace()
response.sendError(401)
}
}

}

authApi授权方法与这个问题无关,但是让它清楚,它永远不会返回null…它可能会抛出异常,但不会返回null

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class SocketIOServerTest {
@MockBean
lateinit var mockedApiComponent: AuthApi

@Autowired
lateinit var boardRepository: BoardRepository

@Autowired
private lateinit var servletRegistrationBean: ServletRegistrationBean<SocketIOServer>
private lateinit var socketIOServer: SocketIOServer
@LocalServerPort
private val serverPort: String? = null
lateinit var clientSocket: Socket
private val userId = 1
private val groupId = 123
private val admin = false
private val auth = Authorization("token", userId, groupId, admin)
private val objectMapper = ObjectMapper()

@BeforeAll
fun connect() {
AuthorizationContext.set(auth)
Mockito.`when`(mockedApiComponent.authorize(anyOrNull())).thenReturn(auth)
socketIOServer = servletRegistrationBean.servlet
clientSocket = IO.socket("http://localhost:${serverPort}", IO.Options.builder().setExtraHeaders(mutableMapOf(Pair("Authorization", listOf("Bearer token")))).build())
clientSocket.on(Socket.EVENT_CONNECT) {
println("client connected")
}
clientSocket.on(Socket.EVENT_DISCONNECT) {
println("client disconnected")
}
clientSocket.connect()
}

@Test
fun testPingPong() {
var finished = false
clientSocket.on("pong") {
println("event: ${it[0]}")
val pongTime = (it[0] as String).substring(18, 31).toLong()
assertTrue(System.currentTimeMillis() - pongTime < 1000)
finished = true
}
clientSocket.emit("ping")
while (!finished) Thread.yield()
}
@Test
fun testBasicNotification(){
clientSocket.on("basic_notification"){
println(Arrays.toString(it))
}
socketIOServer.send(SocketIOEvent("${groupId}","basic_notification","data"))
Thread.sleep(1000)
}
@Test
fun testBoardNotification() {

clientSocket.on("entity_create") {
val event = it[0] as String
println("event: $event")
val eventValue = objectMapper.readValue(event, Map::class.java)
val entityValue = eventValue["entity"] as Map<*, *>
assertEquals("BOARD", eventValue["entity_type"])
assertEquals("board name", entityValue["name"])
assertEquals(groupId, entityValue["groupId"])
assertEquals(userId, entityValue["created_by"])
assertEquals(userId, entityValue["last_modified_by"])

}
val board = boardRepository.save(Board(groupId, "board name"))

//boardRepository.delete(board)
}}

只是为了清楚,测试工作,断言是正确的,虽然它有一些随机的行为在最后它的工作....但是由于一些疯狂的行为,它打印了一个大的堆栈跟踪

正如你所看到的,我正在使用一个SocketIO客户端,它从我的代码中发送几个请求…有些通过了身份验证有些抛出了nullpointerexception

.onSuccess {
AuthorizationContext.set(it) //this line
filterChain.doFilter(request, response)
}.

因为it是null,因为mockedApiComponent.authorize()返回null…同样,这在实际组件上是不可能的,也不应该发生,因为模拟清楚地说明了要返回哪个对象

我已经详尽地调试了这段代码,认为junit不知何故得到了AuthApi的两个bean但是整个执行过程显示了与mock匹配的相同对象id…更奇怪的是,在授权上使用的token参数总是相同的

有人能帮我吗?

我已经彻底调试了这段代码,认为junit以某种方式获得了AuthApi的两个bean,但整个执行显示了与mock匹配的相同对象id…更奇怪的是,授权时使用的令牌参数总是相同的

这看起来让我不安,就像运行时异步代码的一些问题。我会尝试做几件事:

  1. 检查上下文何时为null在:AuthorizationContext.set(it)中并放置一些更多的调试代码以了解正在发生的事情。或者直接从那里调试
  2. 使用recover{}块来处理NullPointerException并从那里调试以查看堆栈跟踪中的原始问题
  3. mapCatching{}代替runCatching{}会发生什么?

最新更新