【问题标题】:Mocking a case class for testing模拟案例类进行测试
【发布时间】:2019-10-06 18:54:46
【问题描述】:

我有一个案例类

case class InputCriteria(a: Int) {
   val b: Int = config.getInt("some path")
}

如何mock这个case类并覆盖b的值?

【问题讨论】:

  • 我的意思是,你问我要说的问题的方式不是答案,但你假设你编写案例类的方式是一个好方法。你为什么不把案例类保留下来,让其他东西根据配置值创建类。您可能永远不需要模拟案例类。
  • 无论如何我都需要覆盖配置值,因为我没有使用任何配置文件进行测试。所以我认为无论我把它放在案例类还是案例类之外都是一样的。请随时纠正我。
  • 不一样,因为无论解析你的配置,都可以在这个特定的测试之外,你可以实例化案例类并将它传递给这个测试,我认为你会让你的生活变得艰难原因

标签: scala scalatest scalamock


【解决方案1】:

试试这个:

object abc extends App {
  case class A() {
    val x = 6
  }

  val a: A = new A() {
    override val x = 9
  }

  println(A().x, a.x)
}

【讨论】:

    【解决方案2】:

    来自 scalamock faq:

    我可以模拟 val/lazy val 吗?

    不,Scala 编译器不允许使用 def 覆盖 val,因此使用 ScalaMock 这是不可能的。我们正在寻找一个可能的 ScalaMock 未来版本的选项是 scala.meta,但它还不适用于我们想要的所有构建目标。如果可以的话,最好用 def 设计一个特征并模拟它。具体实现仍然可以用 val 覆盖该 def 以提供不变的行为。

    如果您将案例类更改为trait,您就可以用proxy.MockFactory 覆盖val

    如果您将val 更改为def,您将能够使用普通模拟覆盖。

    您也可以使用 Raman 的回答中的方法,因此除非您想让您的班级 final 它是有效的解决方案。

    但在我看来,你真正应该做的只是创造特质:

    trait InputCriteria {
         def b: Int
    }
    

    然后实施它:

    case class ConfigDrivenInputCriteria(config: Config) extends InputCriteria {
        override val b: Int = config.getInt("some path")
    }
    

    然后在测试中你可以重新实现它:

    val testInputCritria = new InputCriteria {
        override def b: Int = 4
    }
    

    但如果您在 InputCriteria 中有很多字段,它可能会有点笨拙,但在这种情况下,您也可以模拟它:

    val inputCriteria = stub[InputCriteria]
    (inputCriteria.b _).when().returns(100)
    

    接口 + 实现方法使您能够轻松测试代码。您还可以在实现类时决定您的属性是 defsvals 还是 lazy vals

    【讨论】:

    • 我同意你的做法。但如果有更多的输入标准,我会选择 trait。在我的情况下,我只需要一个输入条件,创建一个特征将添加额外的代码,这对应用程序的其他部分没有用。请随时纠正我。
    • 你是对的,存在该特征的唯一原因是允许更轻松的测试。但在我看来,付出这个代价是值得的,因为这样模拟依赖就简单多了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 2013-08-05
    • 2014-10-23
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    相关资源
    最近更新 更多