Consider the following example Scala class and unit test:
class BrokenClass(s: String) {
private val len = s.length
def length(): Int = len
}
class BrokenTest extends FlatSpec with Matchers with MockFactory {
"A BrokenClass" should "stub correctly" in {
val stubThing = stub[BrokenClass]
(stubThing.length _) when () returns (10)
stubThing.length should equal (10)
}
}
In older versions of ScalaMock, this code would work. With Scala 2.12 and ScalaMock 3.6, I'm getting a NullPointerException because even though I'm creating a stub, it's still invoking the "s.length" line of the constructor of BrokenClass. So it's trying to dereference "s", which is null because I haven't passed anything to it because all I want is a stub that returns a specific value when a specific method is called.
Is there a way to create a stub without it trying to invoke the object's constructor? Why did this work in older versions?
ScalaMock generates subclasses using a macro definition. That macro gets expanded/evaluated during the compiler run.
As mocks are subclasses, the constructors of the superclasses will be called - no exceptions. You might be able to work around this using some cglib sorcery, but that is not something i am familiar with.
So this may have been possible in older ScalaMock versions but this feature is not coming back anytime soon with the current implementation.
another option is to actually subclass this thing yourself and mock the subclass
class NotSoBrokenClass extends BrokenClass("")
...
val nsb = mock[NotSoBrokenClass]
...
That works in some cases, but if the constructor depends on non-final method calls you'll see funny behaviour (e.g. NPEs) too.