【发布时间】:2021-01-25 18:28:06
【问题描述】:
假设我有以下内容:
@ImplementedBy(classOf[DefaultFoo])
trait Foo {
def a (s : String) : Int
}
class DefaultFoo @Inject()() extends Foo{
override def a (s : String) = 1
}
@ImplementedBy(classOf[DefaultBaz])
trait Baz {
def b (s : String) : Int
}
class DefaultBaz @Inject()(val f :Foo) extends Baz{
override def a (s : String) = 1
}
如果我想测试,比如 DefaultBaz,我通常使用 ScalaMock,我会在我的测试规范中模拟如下:
class DefaultBazSpec extends AnyWordSpec with MockFactory{
val mockFoo = mock[Foo]
val b = new DefaultBaz(mockFoo)
// write tests
}
但我也可以这样做:
val mockFoo = mock[DefaultFoo]
哪个更好?模拟 trait 还是默认的类实现?
【问题讨论】:
-
为什么不只是用一个简单的类来扩展特征,它可以做模拟会做的事情,但没有反射和花哨的语法。
-
我没有举一个很好的例子。我想描述一个将
Foo注入另一个类的场景。该类的测试将使用使用 Scalamock 的Foo的模拟版本。现在我可以做mock[Foo]或mock[DefaultFoo]。我想知道这样做的利弊 -
我认为您的 sn-p 中有一些错误,您可能希望
DefaultBaz扩展Baz并接收Foo的实例作为参数。 - 无论如何,我知道您习惯于使用反射来解决 (complicate) 每一个琐碎的问题,例如传递依赖项和测试。但是,Scala 中的许多人更喜欢保持简单,只手动传递依赖项并使用简单的存根进行测试而不是模拟。 -
是的,抱歉,我修复了这个问题,并表明我正在使用 Guice DI 框架。我知道 FP 方法说不要使用 DI,但我使用的是 Play Framework,它带有 Guice DI,所以我正在使用它,这就是我以这种方式进行测试的原因,
-
主要是因为您的
DefaultBaz应该适用于任何Foo,还因为模拟DefaultFoo可能比普通界面更难(顺便说一句,不需要模拟,但你一定厌倦了我一遍又一遍地重复).