user462455
user462455

Reputation: 13588

Singleton pattern in scala that enables easy way to use mocks

I'm working on a use case where my applications needs a singleton object of trait Table. I have a implementation TableImpl() that will be used in development environment. However, I want to be able to switch TableImpl() with MockTableImpl() in test environment.

What is the most scala way to do this?

I can use a factory to serve out singletons of TableImpl(), but how does the factory make the decision of returning a TableImpl() or MockTableImpl()?

Upvotes: 0

Views: 251

Answers (2)

Alvaro Carrasco
Alvaro Carrasco

Reputation: 6172

I would recommend against having a component ask for it's dependencies. Instead, have the creator of the component give it its dependencies (dependency injection or inversion of control). This is an approach that fits much better with idiomatic scala.

Just have dependencies passed as constructor parameters. That way, the class can't be constructed without valid dependencies:

class MyApp (table: Table) {
   ...
}

class TableImpl() extends Table // singleton

// in production
new MyApp (table = new TableImpl()) // or you can use factory or whatever

// in test (assuming scalatest and scalamock)
new MyApp (table = mock[Table])

Upvotes: 1

Przemek Piotrowski
Przemek Piotrowski

Reputation: 7456

trait Table {
  def size: Int
}

object TableImpl extends Table { //SINGLETON
  def size = Math.abs(-5)*11 //real logic
}

Some application class (it may extends App trait).

class AppContext(table: Table) {
  def run = ()
}

Instantiate App using singleton reference.

new AppContext(TableImpl).run

Or construct application context for test reason.

val mock = mock[Table]
//set mock stuff
new AppContext(mock).run 

You are encouraged to use some DI like Macwire, Guice or Cake pattern. My advise is to always make dependencies explicit - do not use singleton object name directly in class body, but inject it.

Upvotes: 2

Related Questions