8

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?

simao
  • 14,491
  • 9
  • 55
  • 66

1 Answers1

16

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.

cmbaxter
  • 35,283
  • 4
  • 86
  • 95