How would I inject a mocked singleton object in Scala?

dependency-injection, mocking, scala

Solution

I don't understand all your classes and your traits.

trait UsersRepo {
    val usersDAO : Users.type = Users
}

trait AnotherRepo {
    val anotherDAO : Another.type = Another
}

trait DAORepo extends UsersRepo with AnotherRepo

And then you can instantiate a real RealDAORepo

object RealDAORepo extends DAORepo { }

Or a mocked one

object MockedDAORepo extends DAORepo {
  override val usersDAO : Users.type = mock[Users]
  override val anotherDAO : Another.type = mock[Another]
}

Then to inject the DAORepo in your application you can use the cake pattern and the self type references to do that.

I'll publish soon an article on InfoQ FR that helps Spring people understand the cake pattern. Here's a code sample from this article:

trait UserTweetServiceComponent {
  val userTweetService: UserTweetService
}

trait UserTweetService {
  def createUser(user: User): User
  def createTweet(tweet: Tweet): Tweet
  def getUser(id: String): User
  def getTweet(id: String): Tweet
  def getUserAndTweets(id: String): (User,List[Tweet])
}

trait DefaultUserTweetServiceComponent extends UserTweetServiceComponent {

  // Declare dependencies of the service here
  self: UserRepositoryComponent 
        with TweetRepositoryComponent =>

  override val userTweetService: UserTweetService = new DefaultUserTweetService

  class DefaultUserTweetService extends UserTweetService {
    override def createUser(user: User): User = userRepository.createUser(user)
    override def createTweet(tweet: Tweet): Tweet = tweetRepository.createTweet(tweet)
    override def getUser(id: String): User = userRepository.getUser(id)
    override def getTweet(id: String): Tweet = tweetRepository.getTweet(id)
    override def getUserAndTweets(id: String): (User,List[Tweet]) = {
      val user = userRepository.getUser(id)
      val tweets = tweetRepository.getAllByUser(user)
      (user,tweets)
    }
  }
}

Note this is almost the same as the Spring declaration:

<bean name="userTweetService" class="service.impl.DefaultUserTweetService">
    <property name="userRepository" ref="userRepository"/>
    <property name="tweetRepository" ref="tweetRepository"/>
</bean>

And when you do:

trait MyApplicationMixin
  extends DefaultUserTweetServiceComponent
  with InMemoryUserRepositoryComponent
  with InMemoryTweetRepositoryComponent

It's almost the same as the Spring declaration (but you get a typesafe application context):

<import resource="classpath*:/META-INF/application-context-default-tweet-services.xml" />
<import resource="classpath*:/META-INF/application-context-inmemory-tweet-repository.xml" />
<import resource="classpath*:/META-INF/application-context-inmemory-user-repository.xml" />

Then you can use the app with:

val app = new MyApplicationMixin { }

Or

val app = new MyApplicationMixin { 
   override val tweetRepository = mock[TweetRepository]
}

The latter will be the same as a Spring bean override:

<import resource="classpath*:/META-INF/application-context-default-tweet-services.xml" />
<import resource="classpath*:/META-INF/application-context-inmemory-tweet-repository.xml" />
<import resource="classpath*:/META-INF/application-context-inmemory-user-repository.xml" />

 <!-- 
 This bean will override the one defined in application-context-inmemory-tweet-repository.xml
 But notice that Spring isn't really helpful to declare the behavior of the mock, which is much 
 easier with the cake pattern since you directly write code
 -->
<bean id="tweetRepository" class="repository.impl.MockedTweetRepository"/>

So to come back to your problem, you could use the cake pattern and create service components in your application, that depend on your DAORepo trait.

And then you can do:

trait MyApplicationMixin
      extends DefaultUserServiceComponent
      with AnotherServiceComponent
      with DAORepo

And then:

val app = new MyApplicationMixin { }

Or

val app = new MyApplicationMixin {
    override val usersDAO : Users.type = mock[Users]
    override val anotherDAO : Another.type = mock[Another]
}

Once your application is built you can use it like that:

app.userService.createUser(...)

The application built is really like an application context

Problem

We're using Scala 2.10.2, and we're using Slick 1.0.1 for our DAOs. We're trying to mock the DAOs with ScalaMock, and I'm trying to figure out a good way to inject the mocked DAOs. I've used Java for several years, but I've just started using Scala two weeks ago. Right now our code looks like (ignore any syntax errors, I've condensed the code without making sure that it still satisfies the type system) ``` abstract class RichTable[T](name: String) extends slick.driver.MySQLDriver.simple.Table[T](name) { type ItemType = T def id = column[Int]("id", O.PrimaryKey, O.AutoInc) ... } object Users extends RichTable[User]("users") { def crypted_password = column[String]("crypted_password") ... } case class User(id: Option[Int] = None, crypted_password: String) { def updatePassword(...) = { Users.where(_.id === id).map{e => e.crypted_password}.update("asdf") } } ``` All of the DAOs are singleton objects inheriting from `RichTable[T]` We'd like to be able to mock Users and the other singleton DAO objects - right now all of our unit tests are hitting the database. However, the problem we're running into is how to inject the mock singleton objects. The solution we've come up with so far is: ``` object DAORepo { var usersDAO : Users.type = Users var anotherDAO : Another.type = Another ... } object Users extends RichTable[User]("users") { def apply() : Users.type = DAORepos.usersDAO } def updatePassword(...) = { Users().where(_.id === id).map{e => e.crypted_password}.update("asdf") } def test = { val mockUsers = mock[Users] DAORepo.usersDAO = mockUsers // run test using mock repo } ``` We're changing all of our references from `Users` to `Users()`, which doesn't add an excessive amount of clutter. However, the use of vars in `DAORepo` smells bad, and I'm wondering if anybody has a suggestion to improve this. I've read Real-World Scala: Dependency Injection (DI) and Component Based Dependency Injection in Scala - I think I understand how to use traits to compose the DAORepo, something like ``` trait UsersRepo { val usersDAO : Users.type = Users } trait DAORepo extends UsersRepo with AnotherRepo { } trait UsersTestRepo { val usersDAO : Users.type = mock[Users] } ``` but I still don't understand how I'd inject the new trait. I could do something like ``` class DAORepoImpl extends DAORepo { } object DAOWrapper { var repo : DAORepo = new DAORepoImpl } def test = { DAOWrapper.repo = new DAORepoImpl with UsersTestRepo } ``` which replaces two dozen vars in `object DAORepo` with a single var in `object DAOWrapper`, but it seems like there ought to be a clean way to do this without any vars.

Original source