Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use mocks with the Cake Pattern

I have the following class:

class LinkUserService() {

  //** cake pattern **
  oauthProvider: OAuthProvider =>
  //******************

  def isUserLinked(userId: String, service: String) = {
    val cred = oauthProvider.loadCredential(userId)
    cred != null

  }

  def linkUserAccount(userId: String, service: String): (String, Option[String]) = {
    if (isUserLinked(userId, service)) {
      ("SERVICE_LINKED", None)
    } else {
      val authUrl = oauthProvider.newAuthorizationUrl
      ("SERVICE_NOT_LINKED", Some(authUrl))
    }
  }

  def setLinkAuthToken(userId: String, service:String, token:String):String = {
    oauthProvider.createAndStoreCredential(userId, token)
  }

}

Typically I'd use this class in production like so:

val linkService = LinkUserService with GoogleOAuthProvider

When it comes to testing, I want to replace the oauthProvider with a mock such that's been trained by my unit test to respond like so: oauthProvider.loadCredential("nobody") returns null. Is this possible? If so, how would I set up my unit test to do so?

like image 825
ThaDon Avatar asked Sep 13 '13 16:09

ThaDon


1 Answers

You have this problem because you are not using cake pattern to full extent. If you write something like

trait LinkUserServiceComponent {
    this: OAuthProviderComponent =>

    val linkUserService = new LinkUserService

    class LinkUserService {
        // use oauthProvider explicitly
        ...
    }
}

trait GoogleOAuthProviderComponent {
    val oauthProvider = new GoogleOAuthProvider

    class GoogleOAuthProvider {
        ...
    }
}

And then you use a mock like this:

val combinedComponent = new LinkUserServiceComponent with OAuthProviderComponent {
    override val oauthProvider = mock(...)
}

Then your problem disappears. If you also make generic interface traits like this (and make other components depend on interface, not on implementation):

trait OAuthProviderComponent {
    def oauthProvider: OAuthProvider

    trait OAuthProvider {
        // Interface declaration
    }
}

then you also would have generic reusable and testable code.

This is very similar to your suggestion and it really is the essence of cake pattern.

like image 124
Vladimir Matveev Avatar answered Sep 29 '22 23:09

Vladimir Matveev