使用 scalamock 在 Scala 中使用 ClassTag 的模拟方法 [英] mocking methods which use ClassTag in scala using scalamock

查看:60
本文介绍了使用 scalamock 在 Scala 中使用 ClassTag 的模拟方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的第一个问题,问题,已回答,但它发现了我遇到的另一个问题.这是场景.

My first question, question, was answered but it uncovered another issue I am having. Here is the scenario.

示例代码(扩展自上一个问题)

Example code (expanded from previous question)

模型:

case class User (first: String, last: String, enabled: Boolean)

组件定义:

trait DataProviderComponent {
  def find[T: ClassTag](id: Int): Try[T]
  def update[T](data: T): Try[T]
}

一个具体的组件实现(更新的实现):

One of the concrete component implementations (updated implementation):

class DbProvider extends DataProviderComponent {
  override def find[T: ClassTag](id: Int): Try[T] = {
    Try {
      val gson = new Gson()
      val testJson = """{"first": "doe", "last": "jane", "enabled": false}"""

      gson.fromJson(testJson, implicitly[ClassTag[T]].runtimeClass).asInstanceOf[T]
    }
  }

  override def update[T](data: T): Try[T] = ???
}

在系统某处隐式使用组件 impl:

Implicit usage of component impl somewhere in system:

implicit val provider = new DbProvider()

class UserRepsitory(implicit provider: DataProviderComponent) {
  def userEnabled(id: Int): Boolean = {
    val user = provider.find[User](id)
    user.isSuccess && user.get.enabled
  }
}

Unit Test1,试图模拟提供者以隔离存储库测试.这不起作用,运行测试时会抛出以下执行.我希望这是因为 ClassTag 的使用,因为当我创建另一个不使用 ClassTag 的示例时,它工作正常.

Unit Test1, trying to mock out provider in order to isolate repository test. This does not work, the following execption is thrown when test is run. I expect it is because of ClassTag usage because when I create another sample which does not use ClassTag, it works fine.

org.scalamock.MockFunction2 不能转换为 org.scalamock.MockFunction1java.lang.ClassCastException: org.scalamock.MockFunction2 不能转换为 org.scalamock.MockFunction1

org.scalamock.MockFunction2 cannot be cast to org.scalamock.MockFunction1 java.lang.ClassCastException: org.scalamock.MockFunction2 cannot be cast to org.scalamock.MockFunction1

class UserRepository$Test1 extends FunSuite with Matchers with MockFactory {
  test("invalid data request should return false") {
    implicit val mockProvider: DataProviderComponent = mock[DataProviderComponent]
    (mockProvider.find[User] _).expects(13).returns(Failure[User](new Exception("Failed!")))

    val repo = new UserRepsitory()
    repo.userEnabled(13) should be (false)
  }
}

Unit Test2 确实有效,但难以维护并且需要更多代码:

Unit Test2 does work but is hard to maintain and requires more code:

class UserRepository$Test2 extends FunSuite with Matchers with MockFactory {
  test("invalid data request should return false") {
    class FakeProvider extends DataProviderComponent {
      override def find[T:ClassTag](id: Int): Try[T] = Failure[T](new Exception("Failed!"))
      override def update[T](data: T): Try[T] = ???
    }

    implicit val provider = new FakeProvider()
    val repo = new UserRepsitory()
    repo.userEnabled(13) should be (false)
  }
}

Unit Test3 确实有效,但 - 仅用于测试 ClassTag 实现:

Unit Test3 does work but - used just to test ClassTag implemenation:

class UserRepository$Test3 extends FunSuite with Matchers with MockFactory {
  test("prove sut works") {
    implicit val provider = new DbProvider()
    val repo = new UserRepsitory()
    val user = repo.userEnabled(13)
    println(user.toString)
  }
}

我使用 ClassTag 是错误还是模拟无法正确模拟它?

Am I using ClassTag wrong or is the mock not able to properly mock it?

推荐答案

这类似于:ScalaMock 用户指南:使用隐式参数模拟方法 - 有一个隐式 ClassTag 参数,所以你必须说服find[T](id:Int)(m: ClassTag[T]) 的 Scala 编译器应该转换为 MockFunction2

This is similar to: ScalaMock User Guide: Mocking methods with implicit params - there is an implicit ClassTag parameter, so you have to convince Scala compiler that find[T](id:Int)(m: ClassTag[T]) should be converted to MockFunction2

以下代码适用于 ScalaMock 3.2:

The following code works with ScalaMock 3.2:

package com.paulbutcher.test.mock

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

import scala.reflect.ClassTag
import scala.util.{ Failure, Try }

case class User(first: String, last: String, enabled: Boolean)

trait DataProviderComponent {
  def find[T: ClassTag](id: Int): Try[T]
  def update[T](data: T): Try[T]
}

class UserRepsitory(implicit provider: DataProviderComponent) {
  def userEnabled(id: Int): Boolean = {
    val user = provider.find[User](id)
    user.isSuccess && user.get.enabled
  }
}

class ClassTagTest extends FlatSpec with ShouldMatchers with MockFactory {
  behavior of "ScalaMock"

  it should "handle mocking methods with class tags" in {
    implicit val mockProvider: DataProviderComponent = mock[DataProviderComponent]
    (mockProvider.find[User](_: Int)(_: ClassTag[User])).expects(13, *).returns(Failure[User](new Exception("Failed!")))

    val repo = new UserRepsitory()
    repo.userEnabled(13) should be(false)
  }
}

这篇关于使用 scalamock 在 Scala 中使用 ClassTag 的模拟方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆