Home > database >  Idiomatic functional way to make in memory repository for tests in Scala
Idiomatic functional way to make in memory repository for tests in Scala

Time:01-15

I have a 2 questions.

  1. I'm making a backend using Akka typed and wanted to make a tests. Simple approeach, no dependency injection, auto-wiring etc. So I have a trait
trait Repository {
  def create(h: Model): Future[Int]

  def get(id: Long): Future[Model]
}

So 2 classes are extending the trait - DatabaseRepository and InMemoryRepository

InMemoryRepository should be used for tests. The simplest solution is to create mutable.Map member for storing entities an update it on each create operation. However, that is mutating a state. I know that these are tests, but even in tests there might be a need for concurrently creating entities.

The other, maybe more functional approach to make a create method returns a Tuple (InMemoryRepository, Int) so it can be passed around when composing Futures, or any effects.

Maybe a solution is to create a simple State monad which would store a Map, implement flatMap method, which can be used in a for comprehension and on all the other places when needed and which hides mutating state.

Do you maybe have a better approach to this?

  1. What is the best approach to pass config values around? I created a package object and have a variables there like dbHost, thirdPartyUrl (loaded from config). Then I include this package object where ever needed.

Thanks in advance

CodePudding user response:

If InMemoryRepository is only used for tests, you don't need to implement it at all. Just use a mock. For example:

   val repo = mock[Repository]
   val models = Seq(mock[Model], mock[Model], mock[Model])
   models.zipWithIndex.foreach { case (m,i) => 
      when(repo.create(m)).thenReturn(Future.successful(i 1))
      when(repo.get(i 1)).thenReturn(Future.successful(m))
   }

Or even simpler, depending on what it is you are actually testing:

   when(repo.create(any)).return(Future.successful(100500))
   when(repo.get(any)).return(Future(mock[Model]))

As for passing config values around, something like (implicit config: Config) is often used.

CodePudding user response:

There is not a single, well documented way, but here is mine. It is a bit long, so I put it on a gist. Abstracting away the container type, as in my project I use both Future and IO: https://gist.github.com/V-Lamp/c8862030a2f9bba4951db985b61719b8

  •  Tags:  
  • Related