Mockk: Using mockkConstructor for File results in StackOverFlowError

Created on 8 Aug 2018  路  6Comments  路  Source: mockk/mockk

Prerequisites

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

  • [x] I am running the latest version
  • [x] I checked the documentation and found no answer
  • [x] 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 ] -----------------------
bug wontfix

Most helpful comment

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.

All 6 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.

Thank you very much for trying to solve it on so short notice and the detailed explanation!

I found a solution in between by using the TemporaryFolder of jUnit, which makes mocking File some kind of obsolete.

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.

Any chance this issue will be fixed in the future?

What is the workaround for this ?

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

Was this page helpful?
0 / 5 - 0 ratings