Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking overloaded method

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?

like image 392
simao Avatar asked May 31 '13 20:05

simao


People also ask

Which methods can be overloaded?

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.

What is a mocked method?

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.

What is mocking in Java?

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.


1 Answers

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.

like image 67
cmbaxter Avatar answered Oct 01 '22 06:10

cmbaxter