2012-05-10 1 views
0

Word 엔티티가 포함 된 Project 엔티티가 있습니다. 내 WordsRepositoryProject 엔티티에 따라 다릅니다. 프로젝트가 포함하는 일련의 단어에 대해 작동해야합니다.모델은 두 개의 리포지토리에 따라 다릅니다. 그들 중 하나를 조롱하는 방법?

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에 대한 의존성 방법을 깨뜨리는 것으로 기억한다. 나에게 조언 해 주실 수 있겠습니까? 각 저장소 또는 하나의 전체 응용 프로그램 클래스에 대해 하나의 팩토리 클래스를 만들 가치가 있습니까? – kseen

+1

각 저장소에 대한 공장. 모든 것을위한 거대한 저장소를 갖는 것은 그 코드 파일을 괴상한 비율로 불러 일으키는 것처럼 보입니다. – Tejs

+0

리포지토리 팩토리 클래스에 해당 기능이 있습니까? 내 프로젝트의 순간에 단지'CreateNewRepository' 메소드가 있고 그것은 바로 그것입니다. 나는이 클래스에서 내가 필요로하는 다른 기능을 상상할 수 없다. – kseen

1

봐 관리 확장 성 프레임 워크로. 기본적으로, 당신은 하나의 인터페이스를 가지고 있고 그 인터페이스 상에 여러 개의 구현을 가지고 있습니다. 하지만 런타임에 이러한 구현을 서로 전환 할 수 있기를 원합니다. 이렇게하기 위해 구현 중 하나에 정적으로 링크 할 수 없으며 프레임 워크에서 어느 것을 사용할 지 결정해야합니다.

MEF는 [가져 오기 (typeof (IWordsRepository))]을 허용합니다. 이렇게하면 배포 항목과 다른 구현으로 드롭 할 수 있습니다. 코드는 다음과 같습니다. 두 개의 서로 다른 DLL을에

[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가 언급하면서. 또 다른 가능성은 setter가 아니라 SetSelectedProject (IWordsRepository) 메서드 일 수 있습니다. 이는 특정 프로젝트에서 가능할 수도 있고 그렇지 않을 수도 있습니다.

+0

답변 해 주셔서 감사합니다. 리팩터링하여 좀 더 이해하기 쉽게 만들 수 있도록 제 코드에 대한 피드백을 주시겠습니까? – kseen

관련 문제