0

I am trying to mock Java generic interface having overloaded method with different number of parameters. Interface code is:

import java.util.concurrent.Callable;

public interface GOInterface<T> {
    void send(T record);
    void send(T record, Callable<T> onComplete);
}

I try to mock the sending with onComplete functionality as follow:

import java.util.concurrent.Callable

import org.scalamock.scalatest.MockFactory
import org.scalatest.{FlatSpec, Matchers}

class JavaInterfaceTest extends FlatSpec with Matchers with MockFactory {
  behavior of "scalamock"

  it should "mock java generic interface with overloaded method (with different number of parameters)" in {
    var result = ""
    val m = mock[GOInterface[String]]
    (m.send(_: String, _: Callable[String])).expects(*, *)
      .onCall{ case(s: String, c: Callable[String]) => c.call()}.once

    m.send("hello", new Callable[String] {
      override def call(): String = {result = "world"; result}
    })

    result should be("world")
  }


  it should "mock java generic interface with overloaded method (with different number of parameters) 2" in {
    var result = ""
    val m = mock[GOInterface[String]]
    (m.send(_: String)).expects(*).once

    m.send("hello")

    result should be("")
  }
}

The error I get from compiler is:

error: value expects is not a member of (String, java.util.concurrent.Callable[String]) => Unit
[ERROR]     (m.send(_: String, _: Callable[String])).expects(*, *)
[ERROR]                                              ^

error: value expects is not a member of String => Unit
[ERROR]     (m.send(_: String)).expects(*).once
[ERROR]    

Looking through the different examples at ScalaMock git I can see there is no test that check Generic Interface with overloaded method having different param count.

My dependencies are:

        <dependency>
            <groupId>org.scalamock</groupId>
            <artifactId>scalamock-scalatest-support_2.11</artifactId>
            <version>3.6.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.scalamock</groupId>
            <artifactId>scalamock-core_2.11</artifactId>
            <version>3.6.0</version>
            <scope>test</scope>
        </dependency>

I created an bug in ScalaMock repo meanwhile.

Noam Shaish
  • 1,613
  • 2
  • 16
  • 37

2 Answers2

2

I managed to to overcome this issue. not in the most clean way but its works. As @PhilippM suggested I needed to fix the type, but unfortunately that was not enough, I needed to create a dummy class. here is the solution which was working for me:

class JavaInterfaceTest extends FlatSpec with Matchers with MockFactory {
  behavior of "scalamock"

  class StringInterface extends GOInterface[String] {
    override def send(record: String): Unit = ()

    override def send(record: String, onComplete: Callable[String]): Unit = ()
  }

  val call: (String, Callable[String]) => Unit = { case(s: String, c: Callable[String]) => c.call()}

  it should "mock java generic interface with overloaded method (with different number of parameters)" in {
    var result = ""
    val m = mock[StringInterface]
    (m.send(_: String, _: Callable[String])).expects(*, *)
      .onCall{ call }.once

    m.send("hello", new Callable[String] {
      override def call(): String = {result = "world"; result}
    })

    result should be("world")
  }


  it should "mock java generic interface with overloaded method (with different number of parameters) 2" in {
    var result = ""
    val m = mock[StringInterface]
    (m.send(_: String)).expects(*).once

    m.send("hello")

    result should be("")
  }
}

I find this a bit ugly and it might be worst when more complicated Interfaces need to be mocked, but I hope its helps others.

Noam Shaish
  • 1,613
  • 2
  • 16
  • 37
  • Definitely agree it's ugly, and unfortunately ScalaMock has a few serious bugs around that area. The macro API is quite complicated to work with, particularly where generics are involved. Glad you got it working! – Philipp May 11 '18 at 09:00
1

first of all i would suggest upgrading to the latest version of ScalaMock, but the corner cases around generics and overloading exist there probably too.

To work around that, in many cases it helps to lock down the type first, then create a mock:

trait StringGoInterface extends GoInterface[String]
val m = mock[StringGoInterface]
Philipp
  • 967
  • 6
  • 16