Search code examples
javascalaunit-testinggenericsscalamock

ScalaMock mocking generic Java interface overloaded method


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.


Solution

  • 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.