I've been trying to mock a `java.io.File` object a...
# mockk
v
I've been trying to mock a
java.io.File
object and it's not going well. I've just seen the documentation that says that this class is restricted by default, and cannot be mocked. I definitely used to be able to... seven years ago! What's the best practice for handling these files in mockk now?
Copy code
private val mockFile: File = mockk()
every { mockFile.name } returns "Simple File (1).md"
With the error message:
Copy code
java.lang.NullPointerException: Cannot invoke "String.lastIndexOf(int)" because "this.path" is null
	at java.base/java.io.File.getName(File.java:456)
	at org.liamjd.bascule.model.BasculePostTest$setup$1.invoke(BasculePostTest.kt:49)
s
You don't need mocks to create a File instance with a specific name. Or do you want to do something more complex?
v
Ah. I suppose you don't. I don't have any complex needs, all I really needed was the name property. So
val mockFile = File("myfile.md")
is working now. Thank you! (Definitely did mockk it 7 years ago...)
s
Mocking a file is still possible but highly discouraged, that is why it has been turned off by default for some classes. And your situation is the perfect example where mocking is a code smell :)
e
https://openjdk.org/jeps/260 Java 9+ prevents you from using non-public parts of system classes (including by reflection) https://openjdk.org/jeps/396 Java 16+ tightens the restrictions further
👀 1
and as Simon says, you shouldn't have been mocking a File in the first place
v
I'm updating an old project I wrote years ago. All the unit tests were written using the Spek framework, which is long dead. So having to start from scratch with unit tests and I'm clearly out of practice.
k
@ephemient while I agree that
File
shouldn't be mocked, can you explain how those two JEPs are relevant to this situation? I don't understand the relevance because the method Liam was trying to mock,
File.getName
, is a public method (and File is an open class) but those JEPs are about encapsulating internals.
m
If you need to fake filesystem operations in your test, I suggest using this library: https://github.com/google/jimfs It worked great for me.
v
Moving project to JVM 21 seems to make mocking much more complicated. I can no longer mock a
data class
- it seems to be
final
now?
io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
I have been mocking a lot of classes that don't really need to be mocked, it seems. Lots of rework for this upgrade...
k
Not just data classes, but most classes in Kotlin are final. It's the default unless you declare them as
open
.
e
or use the allopen plugin
but data classes are another category that you should generally not mock even if you had the ability to
âž• 2
k
Mockk can mock data classes (even with JVM 21). The error message you get suggests you were trying to mock a real object instead of a mock. Having said that I agree it's bad practice to mock data classes. Unless you have a data class with 200 properties without defaults, and you want to test a method that only looks at a couple of those properties. But that would be poor design.
âž• 1