2010-02-17 2 views
2

나는 일정한 데이터베이스 연결에 의존하지 않고 컨트롤러를 테스트 할 수 있도록 정리하는 좋은 방법을 생각하려고합니다. IObjectContext를 사용하여 객체 컨텍스트를 추상화하여 괜찮은 출발을했다고 생각했습니다. 이것은 컨텍스트에서 잘 작동하지만 내 다음 문제는 프로젝트 전체에서 수많은 액션 메소드에서 사용하는 generic repository입니다 (아래 코드 참조).데이터베이스를 치지 않고도 ASP.NET MVC 컨트롤러를 테스트 할 수있는 확실한 방법은 무엇입니까?

기본 생성자 외에 내 컨트롤러는 IObjectContext (간단한 종속성 삽입)를 허용하는 오버로드로 구성됩니다. 유닛 테스트에서 IObjectContext를 쉽게 조롱 할 수 있습니다. 내 문제는 다양한 작업 방법에서 제네릭 저장소를 다루는 것입니다. 컨트롤러에 추가 생성자 오버로드를 추가 할 수는 있지만,이 작업은 지저분해질 수 있습니다. 그러나 그 일을하지 않으면, 테스트 가능성을 개선하기위한 깨끗한 방법을 생각하지 못했기 때문에 데이터베이스 연결에 의존 할 필요가 없습니다.

제가 간과 할 수있는 간단한 해결책이 있습니까?

/// <summary> 
/// Initializes a new instance of the HomeController class 
/// </summary> 
public HomeController(IObjectContext context) 
{ 
    _context = context; 
} 

/// <summary> 
/// GET: /home/index 
/// </summary> 
/// <returns>Renders the home page</returns> 
public ActionResult Index() 
{ 
    List contacts; 
    HomeViewModel model; 

    using (IRepository<Contact> repository = new DataRepository<Contact>(_context)) 
    { 
     contacts = new List(repository.GetAll()); 
    } 

    model = new HomeViewModel(contacts); 

    return View(model); 
}

내 우려를 수용하기 위해 추가 생성자 오버로드를 추가하는 경로를 이동해야하는 경우

, 내 컨트롤러 (필요할 때까지 저장소의 인스턴스를 deffer 것) 개인 특성의 수에 대한 추가 고려하고 액션 메소드가 사용하는 리포지토리 각각. 예를 들어 :

private IRepository<Contact> _contactRepository; 

private IRepository<Contact> ContactRepository 
{ 
    get 
    { 
     return _contactRepository ?? (_contactRepository = new DataRepository<Contact>()); 
    } 
}

단위 테스트의 목적을 위해, 나는 생성자 오버로드를 사용하여 저장소를 미리 초기화 할 수있을 것입니다.

이 점에 대해 어떻게 생각하십니까? 나는 분명해야 할 뭔가를 놓치고 있습니까?

+0

저장소를 조롱 해 주시겠습니까? – Pace

+0

응답 해 주셔서 감사합니다. 사실 그것은 부분적으로 내 요점입니다. 확실히 할 수는 있지만, 컨트롤러를 구현하는 깨끗한 방법으로, 다른 저장소를 사용하는 가능한 각 액션 메소드에 대한 생성자 오버로드가 끝나지 않도록해야할까요? 예를 들어 한 가지 작업 방법은 몇 가지 다른 리포지토리에 의존합니다. – senfo

답변

5

우선 현재 사용중인 바스타드 주입 생성자 오버로드를 제거하십시오. DI를 사용하면 하나의 생성자 만 있으면되고 모든 종속성을 취하는 생성자가 필요합니다. ASP.NET MVC 런타임을 사용하여 컨트롤러를 만들려면 사용자 지정 IControllerFactory를 구현하십시오.

다음 단계는 모든 종속성을 생성자를 통해 주입하는 것입니다. 생성자 매개 변수가 너무 많아서 엉망이된다고 생각하면 Single Responsibility Principle을 위반한다는 좋은 신호입니다. 그런 일이 발생하면 Aggregate Service을 추출합니다.

린스와 반복 :

1

음, 마지막 예제가 내 컨트롤러에 mock을 주입하기 위해 항상 표시하는 것을 수행합니다. 그것은 약간의 냄새가 있습니다 (테스트 가능성을 위해 디자인),하지만 나쁜 코딩이 아니며 테스트를 위해 잘 작동합니다.

1

일반적인 저장소의 사용은 의존성 주입보다 종속성 클로킹 장치 이상입니다. 특정 컨트롤러가 사용하는 모든 종속 관계를 볼 수 있어야합니다. 일반 저장소는 컨트롤러의 창고 깊숙한 곳에서이 사실을 숨겨서 코드 유지 관리 (그리고 단위 테스트)를 훨씬 어렵게 만듭니다. 나의 제안 : 구체적인 저장소를 사용하십시오.

domain-driven design stuff을 살펴볼 수도 있습니다.

관련 문제