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?
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With