0

Twitter、Facebook などへの接続を担当する Social オブジェクトがあり、指定されたユーザーのプロバイダー情報を取得します

プロバイダーごとに、シングルトン TwitterAdapter を実装し、すべて抽象クラス SocialAdapter から継承します。

コードは次のとおりです: https://github.com/RestOpenGov/ideas-ba/blob/master/webservice/app/services/security/SocialConnector.scala#L98

テストのために、Twitter に接続する代わりに固定応答を返すように、明らかに TwitterAdapter をモックしたいと思います。

私が見つけた 1 つの解決策は、暗黙的なパラメーターを使用してアダプターのリストを挿入することでした。このソリューションの問題は、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] = {
  [...]

あなたはアイデアを得る

それは正常に動作します。通常、パラメーターの 2 番目のグループを無視し、Social.defaultAdapters からデフォルトを選択します。テスト時に List(MockTwitterAdapter, MockFacebookAdapter) に設定するだけですが、テストできるようにするためだけにコードを乱雑にしています。 .

もう 1 つの解決策は、Social.defaultAdapters を (val ではなく) var にして、テスト用に変更することです。通常、プロダクション モードでは常に同じ値になります。

これはかなり一般的なシナリオでなければならないと思います。これらの状況を処理するためのより良い戦略はありますか? それとも、暗黙の代入の範囲を拡張する何らかの方法でしょうか? それとも、フル機能の依存性注入フレームワークを使用しますか?

4

1 に答える 1

6

簡単なアプローチは、最初から最後まで特性を使用することです。

// 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(...)
  }
于 2012-10-25T04:47:05.770 に答える