ScalaMock icon indicating copy to clipboard operation
ScalaMock copied to clipboard

Fail to mock Java Generic interface with overloaded method (different number of params)

Open NoamShaish opened this issue 6 years ago • 2 comments

ScalaMock Version

3.6.0

Scala Version

2.11

Runtime

JVM

Please describe the expected behavior of the issue

I would expect to mock Java Generic interfaces having overloaded method with different number of params in the same way I mock other Java interfaces or Scala traits

Please provide a description of what actually happens

When trying to mock this interface I get the following compile error:

 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]                         ^

Reproducible Test Case

import java.util.concurrent.Callable;

public interface GOInterface<T> {
    void send(T record);
    void send(T record, Callable<T> onComplete);
}
it should "mock java generic interface with overloaded method (with different number of parameters)" in {
    import java.util.concurrent.Callable
    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 {
    import java.util.concurrent.Callable
    var result = ""
    val m = mock[GOInterface[String]]
    (m.send(_: String)).expects(*).once

    m.send("hello")

    result should be("")
  }

NoamShaish avatar Apr 26 '18 12:04 NoamShaish

We have several tests related to overloaded methods, have a look here:

https://github.com/paulbutcher/ScalaMock/blob/f20cad77608f3b5f8c67a534b5350632cee7c6f3/jvm/src/test/scala/com.paulbutcher.test/mock/JavaMocksTest.scala#L78-L112

what if you declare trait StringGoInterface extends GoInterface[String] and create a mock[StringGoInterface] instead. That should work

barkhorn avatar May 06 '18 10:05 barkhorn

I looked into the provided tests. even in one of the forks which have more tests. But my edge case isnt covered.

I tried you approach with a trait but I got the same result. The only solution I found was to create a dummy class implementing the interface:

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("")
  }
}

for this example its quit simple but for more complicated interfaces its might be hard/ugly to do.

NoamShaish avatar May 07 '18 08:05 NoamShaish