Simply put, I've got a File
object that product code will invoke the copyTo
method on. Similarly, I'm looking for an equivalent mocking technique for File.inputStream
In the unit test, I just want a mock file and the copyTo call to be a no-op or at best verified.
Simple example:
fun copyFileTest() {
println("start test")
val mockFileSrc = mock(File::class.java)
val mockFileDst = mock(File::class.java)
`when`(mockFileSrc.exists()).doReturn(true)
`when`(mockFileSrc.copyTo(any(), any(), any())).thenAnswer { // DOES NOT WORK
val result = it.arguments[0]
result as File
}
println("done initializing mocks")
Assert.assertEquals(mockFileSrc.exists(), true)
mockFileSrc.copyTo(mockFileDst, true, 0)
println("done with test")
}
When the unit test runs, this exception is thrown:
Parameter specified as non-null is null: method kotlin.io.FilesKt__UtilsKt.copyTo, parameter target
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.io.FilesKt__UtilsKt.copyTo, parameter target
at kotlin.io.FilesKt__UtilsKt.copyTo(Utils.kt)
at com.selibe.myapp.foo.WorkerTest.copyFileTest(WorkerTest.kt:121) <34 internal lines>
at jdk.proxy2/jdk.proxy2.$Proxy5.processTestClass(Unknown Source) <7 internal lines>
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74
I believe the problem may be related to the fact that copyTo
seems to be an extension function.
What's the easiest way to just make copyTo a no-op in the unit test that always succeeds in the unit test?
mockito or mockk solutions are acceptable.
The problem you're having is that File.copyTo
is a Kotlin extension function. Mockito is a Java framework, and doesn't understand anything about Kotlin extension functions.
Java doesn't support extension functions, so what File.copyTo
actually compiles to in JVM bytecode is a static function, a member of class kotlin.io.UtilsKt
, which takes an extra argument at the start of the argument list, representing the receiver object (the source file), like this:
public static final File copyTo(
File $this$copyTo,
File target,
boolean overwrite,
int bufferSize)
If you want to use Mockito to mock this, you'll need to use mockStatic on the kotlin.io.UtilsKt
class and then mock the static method copyTo
. It would be much easier to switch to a mocking framework that is written for Kotlin, such as Mockk, if that is possible.
When using Mockk, to mock module-wide extension functions, use mockkStatic
as per the instructions on the Mockk website. Here's the equivalent of your original code, translated to use Mockk:
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import java.io.File
class MyTest {
@Test
fun copyFileTest() {
println("start test")
val mockFileSrc = mockk<File>()
val mockFileDst = mockk<File>()
mockkStatic(File::copyTo)
every { mockFileSrc.exists() } returns true
every { mockFileSrc.copyTo(any(), any(), any()) } answers {
arg(1) as File // arg(0) is `this` (source), arg(1) is dest
}
println("done initializing mocks")
assertTrue(mockFileSrc.exists())
mockFileSrc.copyTo(mockFileDst, true, 0)
println("done with test")
}
}