ScalaMock имитирует общий перегруженный метод интерфейса Java

Я пытаюсь издеваться над универсальным интерфейсом Java с перегруженным методом с разным количеством параметров. Код интерфейса:

import java.util.concurrent.Callable;

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

Я пытаюсь издеваться над отправкой с помощью функции onComplete следующим образом:

импортировать 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("")
  }
}

Ошибка, которую я получаю от компилятора:

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]    

Просмотр различных примеров на ScalaMock git Я вижу, что нет теста, который проверяет универсальный интерфейс с перегруженным методом, имеющим другое количество параметров.

Мои зависимости:

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

Тем временем я создал ошибку в репозитории ScalaMock.


person Noam Shaish    schedule 25.04.2018    source источник
comment
@PawelWiejacha, возможно, вы можете помочь   -  person Noam Shaish    schedule 25.04.2018


Ответы (2)


Прежде всего, я бы предложил перейти на последнюю версию ScalaMock, но, вероятно, там тоже существуют угловые случаи, связанные с дженериками и перегрузкой.

Чтобы обойти это, во многих случаях помогает сначала заблокировать тип, а затем создать макет:

trait StringGoInterface extends GoInterface[String]
val m = mock[StringGoInterface]
person Philipp    schedule 06.05.2018

Мне удалось преодолеть эту проблему. не самым чистым способом, но работает. Как предложил @PhilippM, мне нужно было исправить тип, но, к сожалению, этого было недостаточно, мне нужно было создать фиктивный класс. вот решение, которое работало для меня:

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

Я нахожу это немного уродливым, и это может быть хуже, когда нужно издеваться над более сложными интерфейсами, но я надеюсь, что это поможет другим.

person Noam Shaish    schedule 07.05.2018
comment
Определенно согласен, что это уродливо, и, к сожалению, в ScalaMock есть несколько серьезных ошибок в этой области. С API макросов довольно сложно работать, особенно когда задействованы дженерики. Рад, что у вас все заработало! - person Philipp; 11.05.2018