I am using scalamock to mock a class that contains some overloaded methods but I am getting some errors.
For example:
val out = mock[PrintStream]
(out.print _).expects("cmd \r\n")
Raises the following error:
[error] [...]/src/test/scala/chili.scala:19: ambiguous reference to overloaded definition,
[error] both method print in class PrintStream of type (x$1: String)Unit
[error] and method print in class PrintStream of type (x$1: Array[Char])Unit
But if I try to use:
(out.print(_: String)).expects("cmd \r\n")
I also get an error:
[info] [...]/src/test/scala/chili.scala:19: Unable to resolve overloaded method print
[info] (out.print(_: String)).expects("cmd \r\n")
[info] ^
[error] [...]/src/test/scala/chili.scala:19: value expects is not a member of String => Unit
[error] (out.print(_: String)).expects("cmd \r\n")
Is there any way to do this in scala? Maybe using another library?
Overloading happens when you have two methods with the same name but different signatures (or arguments). In a class we can implement two or more methods with the same name. Overloaded methods are differentiated based on the number and type of parameter passed as arguments to the methods.
Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls. Through mocking you can explicitly define the return value of methods without actually executing the steps of the method.
Mocking is the act of removing external dependencies from a unit test in order to create a controlled environment around it. Typically, we mock all other classes that interact with the class that we want to test.
I believe the compiler errors you are seeing have to do with the fact that scalamock can not properly mock the PrintStream
class. If look at the scalamock scaladocs you will see the statement:
At present, ScalaMock can only mock traits, Java interfaces, and non-final
classes that define a default constructor
As the PrintStream
class is neither an interface nor does it have default constructor, my guess is that scalamock can not properly mock it and the errors you are seeing are a side effect of that. If you changed your code to use a OutputStream
instead (which is an interface and thus meets scalamock's restrictions), you could do your overloaded method mocking like this:
val mockStream = mock[OutputStream]
(mockStream.write(_:Int)) expects(1)
(mockStream.write(_:Array[Byte])) expects(Array[Byte](1,2,3))
Personally, I prefer Mockito used within Specs2 as it does not have these kinds of restrictions. An example of a class using PrintWriter
and then a test spec for that class using mocking with Mockito is as follows:
import java.io.PrintStream
import java.io.File
import org.specs2.mutable.Specification
import org.specs2.mock.Mockito
class MockitoExample extends Specification with Mockito{
val mockPrinter = mock[PrintStream]
val myPrinter = new MyPrintingClass{
override val printer = mockPrinter
}
"A request to print and attay of strings" should{
"call println on the PrintStream for each string supplied" in {
myPrinter print Array("foo", "bar")
there was one(mockPrinter).println("foo")
there was one(mockPrinter).println("bar")
}
}
}
class MyPrintingClass{
val printer = new PrintStream(new File("foo.txt"))
def print(strings:Array[String]) = strings foreach (printer.println(_))
}
Now this is a very trivial example, using only post-test verifications with no pre-test stubbings (because println
has a Unit
return type), but at least you can see that Mockito does not suffer from the same restrictions as scalamock. You can read more about using Mockito with Specs2 here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With