1

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.

Jose Manuel de Frutos
  • 1,040
  • 1
  • 7
  • 19
Menyten
  • 41
  • 2
  • 5

0 Answers0