mockk: Using mockkConstructor for File results in StackOverFlowError

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • 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

Using mockkConstructor for File should work as expected.

Current Behavior

java.lang.StackOverflowError occurrs

Failure Information (for bugs)

Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template.

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Try to mock File using mockkConstructor

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • MockK version: 1.8.6
  • OS: Mac OS X 10.13.6
  • Kotlin version: 1.2.41
  • JDK version: 1.8u161
  • Type of test: unit test

Failure Logs

Please include any relevant log snippets or files here.

Stack trace

// -----------------------[ YOUR STACK STARTS HERE ] -----------------------
Exception in thread "main" java.lang.StackOverflowError
	at io.mockk.impl.instantiation.JvmConstructorMockFactory$ConstructorInvocationHandler.invocation(JvmConstructorMockFactory.kt:81)
	at io.mockk.proxy.jvm.advice.BaseAdvice.constructorDone(BaseAdvice.kt:33)
	at java.io.File.<init>(File.java:374)
	at sun.misc.URLClassPath$FileLoader.getResource(URLClassPath.java:1279)
	at sun.misc.URLClassPath.getResource(URLClassPath.java:239)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:365)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at io.mockk.impl.instantiation.JvmConstructorMockFactory$ConstructorInvocationHandler.invocation(JvmConstructorMockFactory.kt:81)
// -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------

Minimal reproducible code (the gist of this issue)

// -----------------------[ YOUR CODE STARTS HERE ] -----------------------
package io.mockk.gh

import io.mockk.every
import io.mockk.mockkConstructor
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.File

class FileTest {

    @Test
    fun testConstructorMockkForFile() {
        mockkConstructor(File::class) {
            every {
                anyConstructed<File>().exists()
            } returns true
        }
        assertTrue(File("x").exists())
    }
}
// -----------------------[ YOUR CODE ENDS HERE ] -----------------------

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 8
  • Comments: 15

Commits related to this issue

Most upvoted comments

I performed pretty decent coding effort to make it work.

First, my goal was to solve a problem in general by protecting mockk from recursive calls to Java Library. This didn’t help to solve File issues. It is too tightly coupled to a classloader. Not sure I need to merge this code at all. Will keep it in a branch.

Then I ended up with a solution that scans stack trace and detects the previous call of File method(actually any method alike) if it is a call from Java internals it allows to process it as a regular call. It works, but performance degradation is way too big. Alike 13 seconds for the code you’ve posted.

In general, this integration topic with JVM is a way too complex. I decided to deal with it on best effort basis. Not forbidding it, but not saying that all possible combinations are supported. So that’s it. My best efforts. By closing this issue I conclude that it is very hard to achieve this and is not supported for now.

Any chance this issue will be fixed in the future?

Any news or workaround available? I am also facing same issue- mockkStatic(File::class) every { File(anyString()).exists() } returns true

Any news or workaround available yet? This is a bit of a blocker for us…

What is the workaround for this ?

Happens with URL class as well. Regarding files, I have had success testing files using an in-memory filesystem (as long as you’re using nio everywhere): com.github.marschall:memoryfilesystem - no need to mock in that case.

I found a workaround. In my case I needed to mock writeBytes beforehand

mockkStatic(File::writeBytes)
val slot = slot<File>()
justRun { capture(slot).writeBytes(any()) }
... [execute system under test] ...
slot.captured.path shouldBe "path/name"

Instead of using mockkStatic create a util class lets say(ABCUtil) . And Keep your functions in that util class. Then mock that class using mockkObject(ABCUtil) and test your functions. @oscar0812 @bosankus