我有以下课程:
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)
}
}
通常我会在生产中使用这个类:
val linkService = LinkUserService with GoogleOAuthProvider
在测试时,我想用模拟替换oauthProvider
,这样我的单元测试就会对其进行训练,以便像这样回复:oauthProvider.loadCredential("nobody") returns null
。这可能吗?如果是这样,我将如何设置我的单元测试呢?
答案 0 :(得分:12)
您遇到此问题,因为您没有完全使用蛋糕模式。如果你写了像
这样的东西trait LinkUserServiceComponent {
this: OAuthProviderComponent =>
val linkUserService = new LinkUserService
class LinkUserService {
// use oauthProvider explicitly
...
}
}
trait GoogleOAuthProviderComponent {
val oauthProvider = new GoogleOAuthProvider
class GoogleOAuthProvider {
...
}
}
然后你使用这样的模拟:
val combinedComponent = new LinkUserServiceComponent with OAuthProviderComponent {
override val oauthProvider = mock(...)
}
然后你的问题就消失了。如果你也像这样制作通用接口特性(并使其他组件依赖于接口,而不是实现):
trait OAuthProviderComponent {
def oauthProvider: OAuthProvider
trait OAuthProvider {
// Interface declaration
}
}
然后你也会有通用的可重用和可测试的代码。
这与你的建议非常相似,它确实是蛋糕模式的本质。
答案 1 :(得分:0)
我能够提出的唯一解决办法就是证明了一种代表模拟特征:
trait MockOAuthProvider extends OAuthProvider {
val mockProvider = mock[OAuthProvider]
def loadCredential(userId: String) = mockProvider.loadCredential(userId)
def newAuthorizationUrl() = mockProvider.newAuthorizationUrl
def createAndStoreCredential(userId: String, authToken: String) = mockProvider.createAndStoreCredential(userId, authToken)
}
我把它放在我的规范的顶部,然后当我宣布我的LinkUserService时,我混合了这个Mock特征,如下:
val linkUserService = new LinkUserService() with MockOAuthProvider
val mockOAuth = linkUserService.mockProvider
最后在我的单元测试中,我做了以下的事情:
mockOAuth.loadCredential("nobody") returns null
它有效,但如果我的特性更大,我可以看到它是一个PITA