簡體   English   中英

scala:定義模擬對象,使用隱式注入依賴項的策略

[英]scala: strategy to define mock objects, injecting dependencies using implicits

我有一個社交對象,負責連接到Twitter,facebook等,並檢索指定用戶的提供者信息

對於每個提供程序,我實現了一個單例TwitterAdapter,所有這些都繼承自抽象類SocialAdapter

這是代碼: https : //github.com/RestOpenGov/ideas-ba/blob/master/webservice/app/services/security/SocialConnector.scala#L98

為了進行測試,我顯然想模擬TwitterAdapter,以便與其返回Twitter而不是與Twitter連接,而是返回一些固定的響應。

我發現的一種解決方案是使用隱式參數注入適配器列表。 此解決方案的問題是從其他函數調用了Social.retrieveSocialProviderInfo,因此我必須通過所有調用鏈傳遞隱式List [SocialAdapter]參數,如下所示:

def createApplicationToken(accessToken: AccessToken)
  (implicit adapters: List[SocialAdapter] = Social.defaultAdapters)
: Either[List[Error], ApplicationToken] = {

  // go to social info provider and fetch information
  retrieveProviderInfo(accessToken).fold(
  [...]

def retrieveProviderInfo(accessToken: AccessToken)
  (implicit adapters: List[SocialAdapter] = Social.defaultAdapters)
: Either[List[Error], IdentityProviderInfo] = {
[...]

最后

object Social {

  val defaultAdapters = List(TwitterAdapter, FacebookAdapter)

  def retrieveSocialProviderInfo
    (accessToken: AccessToken)
    (implicit adapters: List[SocialAdapter] = Social.defaultAdapters)   // adapters can be injected
  : Option[IdentityProviderInfo] = {
  [...]

你明白了

它工作正常,通常我只是忽略第二組參數,並從Social.defaultAdapters中選擇默認值,我僅在測試時將其設置為List(MockTwitterAdapter,MockFacebookAdapter),但為了使它能夠測試,我將代碼弄得一團糟。

另一種解決方案是將Social.defaultAdapters設置為var(而不是val),然后將其更改以進行測試,通常在生產模式下,它始終具有相同的值。

我認為這一定是很常見的情況。 是否有更好的策略來應對這些情況? 還是可以通過某種方式來擴展隱式賦值的范圍? 還是我應該使用功能齊全的依賴注入框架?

一個簡單的方法可以是一直使用特征:

// you can test this trait and override the adapters as you wish
// by overriding the defaultAdapters member
trait Social {

  implicit val defaultAdapters = List(TwitterAdapter, FacebookAdapter)

  def retrieveSocialProviderInfo(accessToken: AccessToken):
    Option[IdentityProviderInfo] = ...
}

// you can use this object directly in your production code
// if you don't want to mix it in
object Social extends Social

// or use the trait by mixing it with another
trait Application extends Social {
  def createApplicationToken(accessToken: AccessToken): 
    Either[List[Error], ApplicationToken] = {
    // the defaultAdapters are accessible to the 
    // retrieveProviderInfo method 
    retrieveProviderInfo(accessToken).fold(...)
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM