1

I have a CacheService class that uses an instance of the scala-redis library

class CacheService(redisClient: RedisClient) extend HealthCheck {
  private val client = redisClient

  override def health: Future[ServiceHealth] = {
    client.info
    ...
  }

In my unit test, I'm mocking the client instance and testing the service

class CacheServiceSpec extends AsyncFlatSpec with AsyncMockFactory {
  val clientMock = mock[RedisClient]
  val service = new CacheService(clientMock)

  "A cache service" must "return a successful future when healthy" in {
    (clientMock.info _).expects().returns(Option("blah"))

    service.health map {
      health => assert(health.status == ServiceStatus.Running)
    }
  }
}

yet I'm getting this compilation error

Error:(10, 24) method pipeline overrides nothing.
Note: the super classes of <$anon: com.redis.RedisClient> contain the following, non final members named pipeline:
def pipeline(f: PipelineClient => Any): Option[List[Any]]
  val clientMock = mock[RedisClient]

My research so far indicates ScalaMock 4 is NOT capable of mocking companion objects. The author suggests refactoring the code with Dependency Injection.

  • Am I doing DI correctly (I chose constructor args injection since our codebase is still relatively small and straightforward)? Seems like the author is suggesting putting a wrapper over the client instance. If so, I'm looking for an idiomatic approach.
  • Should I bother with swapping out for another redis library? The libraries being actively maintained, per redis.io's suggestion, use companion objects as well. I personally think this is is not a problem of these libraries.

I'd appreciate any further recommendations. My goal here is to create a health check for our external services (redis, postgres database, emailing and more) that is at least testable. Criticism is welcomed since I'm still new to the Scala ecosystem.

1 Answers1

1

Am I doing DI correctly (I chose constructor args injection since our codebase is still relatively small and straightforward)? Seems like the author is suggesting putting a wrapper over the client instance. If so, I'm looking for an idiomatic approach.

Yes, you are right and this seems to be a known issue(link1). Ideally, there needs to a wrapper around the client instance. One approach could be to create a trait that has a method say connect and extend it to RedisCacheDao and implement the connect method to give you the client instance whenever you require. Then, all you have to do is to mock this connection interface and you will be able to test.

Another approach could be to use embedded redis for unit testing though usually, it is used for integration testing.You can start a simple redis server where the tests are running via code and close it once the testing is done.

Should I bother with swapping out for another redis library? The libraries being actively maintained, per redis.io's suggestion, use companion objects as well. I personally think this is is not a problem of these libraries.

You can certainly do that. I would prefer Jedis as it is easy and it's performance is better than scala-redis(while performing mget).

Let me know if it helps!!

Anand Sai
  • 1,566
  • 7
  • 11