Mockito @mockbean不会在Kotlin上执行
我对Kotlin/Mockito问题
非常
感到 沮丧然后将提供用户验证状态的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 ...它可能会抛出
@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 client,该端子从我的代码中发送了几个请求...其中一些是经过身份验证的,其中有些是在此行上扔nullpointerexception,
.onSuccess {
AuthorizationContext.set(it) //this line
filterChain.doFilter(request, response)
}.
因为 it 是无效的,因为某种程度上mockedapicomponent.authorize()
返回的null ...同样,这是不可能在实际组件上进行的且不应该发生的,因为模拟明确指出了哪个对象返回
我' Ve详尽地删除了此代码,以为Junit以某种方式获得了authapi
的两个豆子 但是,整个执行显示与模拟相匹配的相同对象ID,甚至怪异的令牌
在授权上使用的参数总是相同的
人可以帮助我吗?
I'm super frustrated with a Kotlin/Mockito problem
What I want to accomplish is very simple, I've an AuthorizationFilter on my springboot application and for test purposes I want to mock its behavior to let the test requests pass by
My AuthorizationFilter indeed calls an API which will then provide the user auth status. so I thought that the simplest way to mock this is just have the AuthApi mocked into the filter and return whatever status I want... BUT IT WORKS RANDOMLY
@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)
}
}
}
the authApi authorize method is irrelevant to this question, but just let it be clear it will NEVER return null... it might throw an exception but wont return 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)
}}
Just to be clear, THE TEST WORKS, the assertions are correct and although it has some random behavior at the end it works.... BUT IT PRINTS A BIG STACK TRACE DUE SOME CRAZY BEHAVIOR
As you can see I'm using a SocketIO client which sends several requests out of my code... some of them get authenticated and some of them throw nullpointerexception on this line
.onSuccess {
AuthorizationContext.set(it) //this line
filterChain.doFilter(request, response)
}.
because it
is null, because somehow the mockedApiComponent.authorize()
returned null... again which would be impossible on the real component and which shouldn't be happening because the mock clearly states which object to return
I've exhaustively debbuged this code, thinking that somehow junit got two beans of the AuthApi
but the whole execution shows the same object id which matches the mock... and even weirder that the token
parameter used on authorize is always the same
can anyone help me?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我已经详尽地删除了此代码,以为junit有两个authapi的豆子,但是整个执行显示了与模拟相匹配的相同对象ID,甚至是怪异的,即授权使用的令牌参数始终与此外观 对我来说,就像在运行时异步代码的一些问题一样。我会尝试做几件事:
pretarizationcontext.set(it)
,然后放一些调试代码以了解发生了什么。或者只是从那里进行调试,rection {}
block来处理 nullpointerexception 并从那里进行调试,以查看stack in stack trace trace trace traceruncatching { }
您使用mapCatching {}
?This looks to me disturbing, like some problem with async code at runtime. I would try to do a couple of things:
AuthorizationContext.set(it)
and put some more debug code to know what is happening. Or just debug from thererecover{}
block to deal with the NullPointerException and debug from there to see original problem in stack tracerunCatching{}
you usemapCatching{}
?