ScalaMock
ScalaMock copied to clipboard
Overloaded methods with parameters passed by-name cannot be mocked
I m using ScalaMock to create a stub of the FileSystemManager interface but keep encountering error during compile time because ScalaMock 3 is unable to resolve the overloaded method FileObject resolveFile(String name, FileSystemOptions fileSystemOptions)
. Here is the test demonstrating this problem:
import org.scalatest.FunSuite
import org.scalamock.scalatest.MockFactory
import org.apache.commons.vfs2._
class OverloadedMethodSuite extends FunSuite with MockFactory {
test("stub an overloaded method") {
val s = stub[FileSystemManager]
// ScalaMock 3 is failing at the next line
(s.resolveFile(_: String, _: FileSystemOptions)).when("test", null).returns(null)
assert(s.resolveFile("test", null) == null)
}
}
The error message is as follows:
: Unable to resolve overloaded method resolveFile [info] (m.resolveFile(_: String, _: FileSystemOptions)).when("test", null).returns(null)
I am having the same problem when trying to mock PrintStream#print(_: String)
. Did you find a solution?
I'm also affected by this issue. But the compiler error only happens when one of the overloaded methods has a call-by-name argument. This code:
class OverloadedTest extends FunSpec with MockFactory {
trait ByName {
def call(i: Int)(u: => Unit)
def call()
}
describe("By name") {
it("call overloaded method") {
val byname = mock[ByName]
(byname.call(_:Int)(_:Unit)).expects(10, *)
byname.call(10)(print(""))
}
}
}
Results in: Unable to resolve overloaded method call (byname.call(:Int)(:Unit)).expects(10, *)
If I change def call(i: Int)(u: => Unit)
to def call(i: Int)(u: Unit)
or remove the overloaded def call()
everything works fine.
@ruado1987 In ScalaMock 3.2.1 you can mock FileSystemManager.resolveFile
:
"ScalaMock" should "stub FileSystemManager" in {
import org.apache.commons.vfs2._
val s = stub[FileSystemManager]
(s.resolveFile(_: String, _: FileSystemOptions)) when ("test", null) returns (null)
assert(s.resolveFile("test", null) == null)
}
@simao In ScalaMock 3.2.1 you can mock PrintStream.print
:
it should "mock PrintStream" in {
import java.io.{ OutputStream, PrintStream }
class MockablePrintStream extends PrintStream(mock[OutputStream], false)
val m = mock[MockablePrintStream]
(m.print(_: String)) expects ("foo")
m.print("foo")
}
@zamblauskas You are right - overloaded methods with parameters passed by-name are not currently handled in ScalaMock. I will take care of this soon.
@pawel-wiejacha the change of title isn't quite right, this is also affecting overloaded non passed-by-name methods if one of the parameters is a generic available to the trait.
trait OverloadedMultiParams[A] {
def meth(i: Int, a: A): Int
def meth(): Int
}
val mockTrait = mock[OverloadedMultiParams[String]]
(mockTrait.meth(_: Int, _: String)).expects(1, "Hello").returns(1)
This returns:
Information:(74, 20) Unable to resolve overloaded method meth
(mockTrait.meth(_: Int, _: String)).expects(1, "Hello").returns(1)
^
@trane: thanks - I didn't know about this case. It's a different bug so I created separate issue (#93) for it.
Handling overloaded methods with parameters passed by name can be fixed if we use scala.reflect.internal
API - I've dirty fix ready in my local repository.
when will this issue be released ? need this fix. any workaround ?
At the moment, ScalaMock 4, and fixes for issues like this, depend on Scala.Meta. This has now been released but only supports a subset of Scala versions and only the JVM backend, last time I checked. ScalaMock supports a wider range, so we cannot easily migrate. There are some fundamental limitations of macros. Second parameter lists are always a bit tricky to mock, I find. Maybe using a ProxyMock could be a workaround?
@barkhorn Thank you for your prompt reply. Going forward with the proxy approach at this moment. Waiting for ScalaMock 4 with stability soon :)
My current plan is to keep the 3.x series going as mainline until Scala.meta is available on at least 2.11, 2.12 and JVM+JS. At that time it's probably worth dropping 2.10 support from the 4.x series and doing a revamp to address all the macro problems. At the moment though, 2.10 remains popular due to Spark and SBT, so I am not prepared to make that jump just yet and would rather address some of the fixable issues first to get it as stable as possible.
4.x is still the same as the 3.x series, however the library name and transitive dependencies are changed.
Works with Scala 3