I'm testing my controller containing two endpoints, one for signup and another for signin. Signup is the one failing while signin succeeds.
Here's the stacktrace
Request processing failed: io.mockk.MockKException: no answer found for: AuthService(se.norrskensjakten.norrskensjakten.auth.AuthService#0 bean#1).create(se.norrskensjakten.norrskensjakten.auth.models.Account@611a2d82)
jakarta.servlet.ServletException: Request processing failed: io.mockk.MockKException: no answer found for: AuthService(se.norrskensjakten.norrskensjakten.auth.AuthService#0 bean#1).create(se.norrskensjakten.norrskensjakten.auth.models.Account@611a2d82)
at app//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1019)
at app//org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at app//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at app//org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at app//org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at app//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at app//org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165)
at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at app//org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at app//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at app//org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at app//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at app//org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at app//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at app//org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201)
at app//org.springframework.test.web.servlet.MockHttpServletRequestDsl.perform$spring_test(MockHttpServletRequestDsl.kt:207)
at app//org.springframework.test.web.servlet.MockMvcExtensionsKt.post(MockMvcExtensions.kt:56)
at app//se.norrskensjakten.norrskensjakten.auth.AuthControllerTest.shall successfully create an account(AuthControllerTest.kt:46)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base@17.0.7/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:568)
at app//org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
at app//org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base@17.0.7/java.util.ArrayList.forEach(ArrayList.java:1511)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base@17.0.7/java.util.ArrayList.forEach(ArrayList.java:1511)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base@17.0.7/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:568)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: io.mockk.MockKException: no answer found for: AuthService(se.norrskensjakten.norrskensjakten.auth.AuthService#0 bean#1).create(se.norrskensjakten.norrskensjakten.auth.models.Account@611a2d82)
at app//io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:93)
at app//io.mockk.impl.stub.MockKStub.answer(MockKStub.kt:42)
at app//io.mockk.impl.recording.states.AnsweringState.call(AnsweringState.kt:16)
at app//io.mockk.impl.recording.CommonCallRecorder.call(CommonCallRecorder.kt:53)
at app//io.mockk.impl.stub.MockKStub.handleInvocation(MockKStub.kt:271)
at app//io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:24)
at app//io.mockk.proxy.jvm.advice.Interceptor.call(Interceptor.kt:21)
at app//se.norrskensjakten.norrskensjakten.auth.AuthService.create(AuthService.kt:16)
at app//se.norrskensjakten.norrskensjakten.auth.AuthController.signup(AuthController.kt:17)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base@17.0.7/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:568)
at app//org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
at app//org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
at app//org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at app//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
at app//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at app//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at app//org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
at app//org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
at app//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
... 105 more
Here's my controller
package se.norrskensjakten.norrskensjakten.auth
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController
import se.norrskensjakten.norrskensjakten.auth.models.Account
import se.norrskensjakten.norrskensjakten.auth.models.LoginDetails
import se.norrskensjakten.norrskensjakten.auth.models.User
@RestController
class AuthController(val service: AuthService) {
@PostMapping("/signup")
@ResponseStatus(HttpStatus.CREATED)
fun signup(@RequestBody account: Account) = service.create(account)
@PostMapping("/signin")
fun signin(@RequestBody loginDetails: LoginDetails): User = service.login(loginDetails)
}
Here's my service
package se.norrskensjakten.norrskensjakten.auth
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.server.ResponseStatusException
import se.norrskensjakten.norrskensjakten.auth.models.Account
import se.norrskensjakten.norrskensjakten.auth.models.LoginDetails
import se.norrskensjakten.norrskensjakten.auth.models.User
import se.norrskensjakten.norrskensjakten.auth.models.toUser
@Service
class AuthService(val repository: AuthRepository) {
fun create(account: Account) {
repository.save(account)
}
fun login(loginDetails: LoginDetails): User {
val (email, password) = loginDetails
val result = repository.findByEmail(email)
if (result != null && result.password == password) {
return result.toUser()
}
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Wrong email or password")
}
}
and here's my tests
package se.norrskensjakten.norrskensjakten.auth
import com.fasterxml.jackson.databind.ObjectMapper
import com.ninjasquad.springmockk.MockkBean
import io.mockk.*
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.post
import se.norrskensjakten.norrskensjakten.auth.models.Account
import se.norrskensjakten.norrskensjakten.auth.models.LoginDetails
import se.norrskensjakten.norrskensjakten.auth.models.User
@WebMvcTest(AuthController::class)
class AuthControllerTest {
@MockkBean
private lateinit var authService: AuthService
@Autowired
private lateinit var mockMvc: MockMvc
@BeforeEach
fun beforeEach() {
clearAllMocks()
}
@Test
fun `shall successfully create an account`() {
// Arrange
val account = Account(
username = "Blabla",
email = "blabla@gmail.com",
password = "password",
firstName = "Bla",
lastName = "Bla",
)
every { authService.create(account) } just Runs
// Act
val result = mockMvc.post("/signup") {
contentType = MediaType.APPLICATION_JSON
content = toJson(account)
}
// Assert
result.andExpect { status { isCreated() } }
}
@Test
fun `shall successfully login a user`() {
// Arrange
val loginDetails = LoginDetails(email = "blabla@gmail.com", password = "password")
val user = User(
id = 1,
username = "Blabla",
email = "blabla@gmail.com",
firstName = "Bla",
lastName = "Bla",
)
every { authService.login(loginDetails) } returns user
// Act
val result = mockMvc.post("/signin") {
contentType = MediaType.APPLICATION_JSON
content = toJson(loginDetails)
}
// Assert
result.andExpect {
status { isOk() }
content { toJson(user) }
}
}
private fun <T> toJson(clazz: T): String {
val objectMapper = ObjectMapper()
return objectMapper.writeValueAsString(clazz)
}
}
package se.norrskensjakten.norrskensjakten.auth.models
import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
@Entity
class Account(
@Id
@GeneratedValue
var id: Long? = null,
@Column(unique = true)
var username: String,
@Column(unique = true)
var email: String,
var password: String,
var firstName: String,
var lastName: String,
)
fun Account.toUser() = User(
id = id,
username = username,
email = email,
firstName = firstName,
lastName = lastName,
)
package se.norrskensjakten.norrskensjakten.auth.models
data class LoginDetails(
var email: String,
var password: String,
)
I've figured out that it has something to do with the every { authService.create(account) } just Runs
because if I change it to every { authService.create(any<Account>()) } just Runs
it works just fine. But I'm trying to make sure that the authService is called with the exact same values in the account instance, but it doesn't seem to work for some reason. But for some reason it works in the signin test. Maybe my thinking is off, but I wanted to avoid using any when mocking the authservice.create call.