Scala: Mocking and the Cake Pattern

后端 未结 4 934
梦如初夏
梦如初夏 2021-02-03 11:32

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

4条回答
  •  刺人心
    刺人心 (楼主)
    2021-02-03 12:15

    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
    

提交回复
热议问题