斯卡拉:嘲弄和蛋糕模式

Ele*_*onk 10 scala mocking

我一直在尝试采用Cake Pattern,但我很难适应这种编程风格,特别是在涉及单元测试的情况下.

让我们假设我有以下业务对象:

trait Vet {
  def vaccinate(pet: Pet)
}

trait PetStore { this: Vet =>
  def sell(pet: Pet) {
    vaccinate(pet)
    // do some other stuff
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想在模拟Vet的功能时测试PetStore.如果我正在使用合成,我正在创建一个模拟[Vet]并将其传递给PetStore构造函数,然后像在Java世界中那样编写模拟.但是,我找不到人们如何用蛋糕模式做这个的任何参考.

一种可能的解决方案是根据预期的用法在每个测试用例上实施vaccinate(),但这不允许我验证模拟被正确调用,不允许我使用匹配器等.

那么 - 人们如何使用Cake Pattern与模拟对象?

Tra*_*ens 6

我在阅读这篇博文后开始使用蛋糕模式:https://github.com/precog/staticsite/blob/master/contents/blog/Existential-Types-FTW/index.md 这种方法与大多数蛋糕模式不同使用那些存在类型的帖子而不是自我类型.

我已经使用这种模式几个月了,它看起来效果很好,因为我可以在我想要的时候指定一个模拟.它确实具有更多的依赖注入感觉,但它具有使您的代码具有特征的所有好处.

我使用存在类型的问题的混蛋版本将是这样的:

case class Pet(val name: String)
trait ConfigComponent {
  type Config
  def config: Config
}

trait Vet {
  def vaccinate(pet: Pet) = {println ("Vaccinate:" + pet)}
}

trait PetStoreConfig {
  val vet: Vet
}
trait PetStore extends ConfigComponent {

    type Config <: PetStoreConfig

    def sell(pet: Pet) {
      config.vet.vaccinate(pet)
      // do some other stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以把它们放在你的应用程序中

class MyApp extends PetStore with PetStoreConfig {

  type Config = MyApp
  def config = this  

  val vet = new Vet{}
  sell(new Pet("Fido"))

}

scala> new MyApp
Vaccinate:Pet(Fido)
res0: MyApp = MyApp@668dd96c
Run Code Online (Sandbox Code Playgroud)

您可以通过创建VetLike实例来单独测试组件,还可以使用PetStore测试创建VetLike的模拟.

//Test VetLike Behavior
scala> val vet = new Vet{}
scala> vet.vaccinate(new Pet("Fido"))
Vaccinate:Pet(Fido)


//Test Petstore Behavior

class VetMock extends Vet {
   override def vaccinate(pet: Pet) = println("MOCKED")
}

class PetStoreTest extends PetStore with PetStoreConfig {
   type Config = PetStoreTest
   def config = this

   val vet = new VetMock
   val fido = new Pet("Fido")
   sell(fido)
}

scala> new PetStoreTest
MOCKED
Run Code Online (Sandbox Code Playgroud)


Ric*_*777 5

这是一个好问题。我们得出的结论是这是不可能做到的,至少与我们习惯的方式不一样。可以使用存根代替模拟,并以蛋糕方式混合存根。但这比使用模拟需要更多工作。

我们有两个 Scala 团队,一个团队采用了蛋糕模式,使用存根而不是模拟,而另一个团队则坚持类和依赖注入。现在我已经尝试了两者,我更喜欢带有模拟的 DI,因为它更容易测试。而且可以说也更容易阅读。