2012-05-10 1 views
0

私はWordエンティティのセットを持つProjectエンティティを持っています。私のWordsRepositoryは、Projectエンティティによって異なります。それは、プロジェクトに含まれる言葉のセットを操作する必要があります。モデルは2つのリポジトリによって異なります。そのうちの1つを模擬する方法は?

public interface IWordsRepository 
{ 
    List<Word> FetchAll(); 
} 
public class WordsRepository : IWordsRepository 
{ 
    private readonly Project _project; 

    public WordsRepository(Project project) 
    { 
     if (project == null) 
      throw new ArgumentNullException("project"); 
     this._project = project; 
    } 
    public List<Word> FetchAll() 
    { 
     // code for retrieveing words for the project from the database 
    }   
} 

もう少し深く掘り下げてみましょう。ここに私のProjectsModelです。モデルの選択したプロジェクトが変更された場合

public class ProjectsModel 
{ 
    private readonly IProjectsRepository _rep; 
    private IWordsRepository _wordsRep; 
    private IProjectsModelObserver _presenter; 

    // Regular contructor for usual purpose 
    public ProjectsModel() 
    {    
     this._rep = new ProjectsRepository(Program.context); 
    } 

    public ProjectsModel(IProjectsRepository repository) 
    { 
     this._rep = repository; 
    } 

    public virtual void AttachPresenter(IProjectsModelObserver observer) 
    { 
     this._presenter = observer; 
    } 

    public List<Project> projects 
    { 
     get 
     { 
      List<Project> tmpList = _rep.FetchAll(); 
      return (tmpList != null) ? tmpList : new List<Project>(); 
     } 
    } 

    private Project _selectedProject; 
    public Project selectedProject 
    { 
     get 
     { 
      if (_selectedProject == null) 
       _selectedProject = projects.FirstOrDefault(); 
      return _selectedProject; 
     } 
     set 
     { 
      if (!projects.Contains(value)) 
       throw new InvalidOperationException("Project not in the Projects list"); 

      _selectedProject = projects[projects.IndexOf(value)]; 
      // Recreating Words repository depending on project 
      // Here is my issue: 
      // As I should recreate the Words repository here, passing a new selected project 
      // how can I mock it and make this class testable? 
      this._wordsRep = new WordsRepository(this._selectedProject); 

      if (this._presenter != null) 
       this._presenter.SelectedProjectChanged(_selectedProject); 
     } 
    } 

    private List<Word> _words; 
    public List<Word> Words 
    { 
     get 
     { 
      // Fetching set of words in Project. Just invoking a words repository 
     } 
    } 
} 

、それはWordsRepositoryを再作成する必要がありますが、この方法テスト可能ではありません。

どうすれば偽装できますか?

答えて

2

新しいWordsRepositoryを作成するには、工場を使用する必要があります。ご存知のように、コードにnewという単語が表示されている場合は、テスト時に必要なインスタンスを返すようにファクトリをモックすることができるため、そのインスタンスを要求するFactoryクラスを作成することをお勧めします。

ですから、これに変更します

_WordsRep = WordsRepositoryFactory.CreateNewRepository(_selectedProject); 
+0

ありがとうございます!本当に良いアイデアです!私はちょうどRoy Asheroveの.net unit testing bookに関する本の中で、依存する方法の一つとして覚えています。私はアドバイスできますか?それぞれのリポジトリまたは1つのアプリケーション全体のレポクラスに対して1つのファクトリクラスを作成する価値はありますか? – kseen

+1

各リポジトリの工場。すべてのための巨大なリポジトリを持っていることは、そのコードファイルを巨大な割合に膨張させるように思えます。 – Tejs

+0

レポジトリの工場クラスにはその機能がありますか?私のプロジェクトの現時点では、単に 'CreateNewRepository'メソッドがあります。それはそれです。私はこのクラスで必要とする他の機能を想像することはできません。 – kseen

1

は、マネージド拡張フレームワークに見て。基本的に、そのインタフェース上に複数の実装を持つ単一のインタフェースがあります。しかし、実行時には、これらの実装を相互に切り替えることができるようにしたいと考えています。そのためには、どちらの実装に対しても静的にリンクすることはできません。また、どちらを使用するかをフレームワークが判断できるようにする必要があります。

MEFでは[インポート(typeof(IWordsRepository))]が可能です。これにより、配備アイテムとは異なる実装にドロップできます。コードは次のようになります。二つの異なるのDLLでこれらの2つのタイプ

[Import(typeof(IWordsRepository))] 
IWordsRepository _repo; 

ストア、およびテストは、あなたのユニットテストの展開項目として入力ドロップ:

[Export(typeof(IWordsRepository))] 
public class WordsRepository : IWordsRepository 
{ 
    public List<Word> FetchAll() 
    { 
     //this class will hit the database 
    } 
} 



[Export(typeof(IWordsRepository))] 
public class WordsRepositoryTest : IWordsRepository 
{ 
    public List<Word> FetchAll() 
    { 
     //this class will not go to the database, maybe an xml file or something.  
    } 
} 

次に、あなたのProjectsModelが使用されます。それはあなたがドロップする方の実装に使用するMEF上

より:展開項目の http://msdn.microsoft.com/en-us/library/dd460648.aspx

より: http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.deploymentitemattribute(v=vs.80).aspx

0

私は理解しにくいコードを見つけるんだけど、工場はオプションですTejsが言及しているように。もう一つの可能​​性は、セッターを持たないことですが、SetSelectedProject(IWordsRepository)メソッドです。これはあなたの特定のプロジェクトで可能性があります。

+0

お返事ありがとうございます!私はリファクタリングして理解しやすくするために、私のコードについていくつかのフィードバックをお願いしますか? – kseen

関連する問題