8000 Allow suppressing "Failed to set backing field" OR fail test · Issue #1291 · mockk/mockk · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Allow suppressing "Failed to set backing field" OR fail test #1291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 tasks done
cgm-aw opened this issue Aug 29, 2024 · 6 comments
Closed
3 tasks done

Allow suppressing "Failed to set backing field" OR fail test #1291

cgm-aw opened this issue Aug 29, 2024 · 6 comments

Comments

@cgm-aw
Copy link
Contributor
cgm-aw commented Aug 29, 2024

Introduction

Hi everyone,

I encountered a behavior of mockk, where, if the backing field has a different type than the getter, a warning is printed to the logs but the test continues and passes.
This seems weird to me - I would either expect the test to fail or no warning message.
My suggestion:
Add a parameter to the mockk() function to be able to suppress the warning, and if suppression is not active, the test will fail (or the other way around).

I'm aware of this: https://mockk.io/#property-backing-fields
With the solution presented there, everything works fine. However, if you do not use this mechanism, you will just get confusing error messages and probably an inconsistent behavior.

Prerequisites

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

Expected Behavior

Either a broken test or no log message

Current Behavior

A warning message is printed, including a stack trace, but the test passes

Steps to Reproduce

Create this class (this is a Java class!)

import java.util.Optional;

public class ContainerClass {
    private Optional<String> someField;
    public String getSomeField() {
        return someField.orElse("empty");
    }
}

Create this Kotlin test:

    @kotlin.test.Test
    fun reproduceFailedToSetBackingField() {
        val testObject = mockk<ContainerClass>()

        every { testObject.someField } returns "mockValue"

    }

You will see this log entry:

2024-08-29 07:37:00,610 [main] WARN  i.m.i.r.states.StubbingAwaitingAnswerState - Failed to set backing field (skipping)
java.lang.IllegalArgumentException: Can not set java.util.Optional field test.ContainerClass.someField to java.lang.String
[...]

Using propertyType yields the correct behavior:
every { testObject.someField } propertyType Optional::class answers { "mockValue" }

Context

  • MockK version: 1.13.12
  • OS: MacOS
  • Kotlin version:2.0.20
  • JDK version: 21
  • JUnit version: 5.10.1
  • Type of test: unit test

Stack trace

// -----------------------[ YOUR STACK STARTS HERE ] -----------------------
2024-08-29 07:37:00,610 [main] WARN  i.m.i.r.states.StubbingAwaitingAnswerState - Failed to set backing field (skipping)
java.lang.IllegalArgumentException: Can not set java.util.Optional field test.ContainerClass.someField to java.lang.String
	at java.base/jdk.internal.reflect.FieldAccessorImpl.throwSetIllegalArgumentException(FieldAccessorImpl.java:228)
	at java.base/jdk.internal.reflect.FieldAccessorImpl.throwSetIllegalArgumentException(FieldAccessorImpl.java:232)
	at java.base/jdk.internal.reflect.MethodHandleObjectFieldAccessorImpl.set(MethodHandleObjectFieldAccessorImpl.java:115)
	at java.base/java.lang.reflect.Field.set(Field.java:836)
	at io.mockk.InternalPlatformDsl.dynamicSetField(InternalPlatformDsl.kt:182)
	at io.mockk.impl.recording.states.StubbingAwaitingAnswerState.assignFieldIfMockingProperty(StubbingAwaitingAnswerState.kt:68)
	at io.mockk.impl.recording.states.StubbingAwaitingAnswerState.access$assignFieldIfMockingProperty(StubbingAwaitingAnswerState.kt:9)
	at io.mockk.impl.recording.states.StubbingAwaitingAnswerState$assignFieldIfMockingProperty$1.invoke(StubbingAwaitingAnswerState.kt:52)
	at io.mockk.impl.recording.states.StubbingAwaitingAnswerState$assignFieldIfMockingProperty$1.invoke(StubbingAwaitingAnswerState.kt:51)
	at io.mockk.impl.stub.AnswerAnsweringOpportunity.notifyFirstAnswerHandlers(AnswerAnsweringOpportunity.kt:30)
	at io.mockk.impl.stub.AnswerAnsweringOpportunity.provideAnswer(AnswerAnsweringOpportunity.kt:21)
	at io.mockk.MockKStubScope.answers(API.kt:2292)
	at io.mockk.MockKStubScope.returns(API.kt:2296)
	at test.CustomersPojoTest.reproduceFailedToSetBackingField(CustomersPojoTest.kt:102)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.e
8000
ngine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85)
	at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
// -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------

Minimal reproducible code (the gist of this issue)

See above

@PavlosTze
Copy link

I'm also encountering the same issue. @Raibaz @zkkv @ any ideas?

@bjpe
Copy link
bjpe commented Nov 5, 2024

Hi, I also got the same problem today. @cgm-aw : Could you elaborate how you circumvented this issue using https://mockk.io/#property-backing-fields? Maybe you could just provide the adjusted test code. My current attempts do not work, unfortunately.

@cgm-aw
Copy link
Contributor Author
cgm-aw commented Nov 5, 2024

Hi @bjpe

yes I added it to the description. Use this:
every { testObject.someField } propertyType Optional::class answers { "mockValue" }

I also noticed that formatting in my post was a mess, I fixed that.

@bjpe
Copy link
bjpe commented Nov 6, 2024

Hi @cgm-aw , thank you very much! I also tried this, but it failed in my case because the field is not accessible (the mocked class is located in a library). Anyway, thanks a lot!

@p4ulor
Copy link
Contributor
p4ulor commented Dec 28, 2024

I have a similar issue. I'm in Android, using RectF from android.graphics
Mockk doesn't seem to access java fields

val rect = mockk<RectF>(relaxed = true) {
    every { width() } returns 1600f
    every { height() } returns 900f

    every { left } returns 0f // error: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
    every { getProperty("left") } propertyType java.lang.Float::class answers { 0f } // error: can't find property left for dynamic property get

}

@cgm-aw
Copy link
Contributor Author
cgm-aw commented Feb 17, 2025

I'm not really happy with the solution - in my mind, this is a bug because the developer wanted to mock something which just does not work. I added a PR with a proposal for a fix: #1349

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants
0