Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Mocking and the Cake Pattern

Tags:

mocking

scala

I've been trying to adopt the Cake Pattern but I'm having difficulties adapting to this programming styles, especially where unit tests are concerned.

Lets assume that I have the following business objects:

trait Vet {
  def vaccinate(pet: Pet)
}

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

Now, I'd like to test PetStore while mocking out the functions from Vet. If I was using composition, I was creating a mock[Vet] and passing it to the PetStore constructor, then programming the mock like we do in the Java world. However, I can't find any reference to how people do this with the cake pattern.

One possible solution would be to implement vaccinate() on each test case according to the expected usage, but this then doesn't allow me to verify that the mocks were called properly, doesn't allow me to use matchers, etc.

So - how are people using Cake Pattern with mock objects?

like image 881
Electric Monk Avatar asked Apr 29 '13 09:04

Electric Monk


2 Answers

I started using the cake pattern after I read this blog post: https://github.com/precog/staticsite/blob/master/contents/blog/Existential-Types-FTW/index.md The approach is different from most Cake Pattern posts in that existential-types are used instead of self-types.

I have been using this pattern for a few months and it seems to work out well as I can specify a mock when I want to. It does have more a dependency injection feel to it, but it has all the benefits you get of having your code in traits.

My bastardized version of your problem using existential-types would be something like this:

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

You can put it all together in your app

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

And you can test the components individually by creating an instance of VetLike and also creating a mock of VetLike an using it your PetStore test.

//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
like image 76
Travis Stevens Avatar answered Sep 30 '22 03:09

Travis Stevens


It's a good question. We came to the conclusion it can't be done, at least not quite the same way we're used to. It's possible to use stubs instead of mocks and mix the stubs in cake-wise. But this is more work than using mocks.

We have two Scala teams and one team adopted the cake pattern, using stubs instead of mocks, whilst the other team stuck to classes and dependency injection. Now I've tried both, I prefer DI with mocks due to it being simpler to test. And arguably simpler to read too.

like image 43
Rick-777 Avatar answered Sep 30 '22 02:09

Rick-777