2013-08-19 2 views
0

당신이 MOQ와 정적 메서드를 조롱 할 수 있음을 이해하지만 내 가능한 옵션이 비웃음 정적 메소드 옵션

내가 컨트롤러 클래스는

public class CustomerController : BaseController 
{ 
    private ICustomerManager cm; 

    public CustomerController() 
     : this(new CustomerManager()) 
    { 
    } 

    public CustomerController(ICustomerManager customerMan) 
{ 
    cm = customerMan; 
} 

    public ActionResult EditContact(ContactVM model, IEnumerable<HttpPostedFileBase> Files, PageAction pageAction) 
    { 
     if (ModelState.IsValid) 
     { 
      InitializeContactVM(model); //throws an error 
     } 
    } 

    private void InitializeContactVM(ContactVM model) 
    { 
     model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId); 
     model.ContactClassificationList = AddBlankToList(SelectLists.ContactClassifications(false)); 
     model.ContactSourceList = AddBlankToList(SelectLists.ContactSources(false)); 
    } 
} 

그리고 내 장치를 정의가 무엇인지 궁금 해서요 시험은 다음과 같습니다

public void Edit_Contact_Update_Existing_Contact() 
{ 
    var dataManager = new Mock<IReferenceDataManager>(); 
    //dataManager.Setup(a=>a.GetContactClassifications()).Returns() 
    var contact = InitializeContact(); 
    var contactvm = new ContactVM(contact); 
    var fileMock = new Mock<HttpPostedFileBase>(); 
    var files = new[] {fileMock.Object}; 

    var mocManager = InitializeMocManagerContact(); 
    mocManager.Setup(a => a.GetContactById(It.IsAny<int>())).Returns(contact); 
    mocManager.Setup(a => a.UpdateContact(It.IsAny<ContactVM>(), It.IsAny<string>())).Returns(contact); 

    var controller = new CustomerController(mocManager.Object); 
    var controllerContext = InitializeContext(); 
    controller.ControllerContext = controllerContext.Object; 
    // mocManager.CallBase = true; 

    var result = controller.EditContact(contactvm, files, PageAction.Default) as ViewResult; 
    var model = result.ViewData.Model as ContactVM; 

    Assert.IsTrue(model.ContactId == contact.CONTACT_ID); 
} 

문제는이 SelectLists.ContactClassifications (거짓)이, 그 다음 데이터베이스에 접속하려고 호출하는 개인 방법입니다.

selectList의 클래스는

public static class SelectLists 
{ 
    private static readonly ReferenceDataManager _dataManager = new ReferenceDataManager(); 

    public static SelectList ContactClassifications(bool includeDeleted) 
    { 
     var data = _dataManager.GetContactClassifications(); 
    } 
} 

같이 정의되며, 그것은 그것이 내가 (조롱 할 수있을 것 같은 느낌이 있다는 selectList의에서 GetContactClassifications를 호출하는 라인의 경우가 될 수 없다 호출하는 방법 그것은 정적이기 때문에 조롱을 받았다). 이것은 인터페이스를 구현합니다.

Controller (InitialiseContactVM)의 개인 메소드가 조롱받을 수있는 몇 가지 방법이 있더라도 그것은 나에게 적합 할 것입니다.

이러한 작업을 수행 할 수있는 방법이 있습니까?

답변

1

이상적으로 DAL은 정적 방법으로 만들어져서는 안되며 인터페이스를 통해 컨트롤러에 주입 된 서비스를 제공하는 일반 개체 또는 필요한 모든 개체가 있어야합니다.

하지만 변경할 수 없다면 컨트롤러에서 정적 메서드 호출을 분리하는 것이 가장 좋은 방법 일 것입니다. 정적 호출을 포함하는 클래스에서 래핑하여 수행 할 수 있으며 인터페이스를 구현합니다.이 인터페이스는 컨트롤러에 삽입되어 테스트에서 조롱됩니다. MessageBox 호출이나 현재 시스템 날짜/시간을 테스트하는 것과 다소 비슷합니다. 먼저 정적 메소드를 포함하는 인터페이스를 만들

호출 :

public interface ISelectListsWrapper 
{ 
    SelectList ContactClassifications(bool includeDeleted); 
} 

그런 클래스는 실제 정적 메서드 호출하여 구현됩니다

public class SelectListsWrapper : ISelectListsWrapper 
{ 
    public SelectList ContactClassifications(bool includeDeleted) 
    { 
     return SelectLists.ContactClassifications(includeDeleted); 
    } 
} 

컨트롤러에서를, 당신은을 이 클래스의 인스턴스를 생성자에 저장하고 로컬 변수에 저장 한 다음이를 사용하여 래퍼를 통해 정적 메서드를 호출합니다.

private readonly ISelectListsWrapper selectLists; 

public CustomerController(ICustomerManager customerMan, ISelectListsWrapper selectLists) 
{ 
    cm = customerMan; 
    this.selectLists = selectLists; 
} 

private void InitializeContactVM(ContactVM model) 
{ 
    model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId); 
    model.ContactClassificationList = AddBlankToList(this.selectLists.ContactClassifications(false)); 
    model.ContactSourceList = AddBlankToList(this.selectLists.ContactSources(false)); 
} 

마지막으로, 테스트에서는 래퍼 모크를 전달하고 테스트에서 의미가있는 것을 반환하도록 설정합니다.

+0

환호 Alejandro, 답장을 보내 주셔서 대단히 감사합니다. 변경을했으며 작동 중입니다. 나를 위해 잘 – jazza1000

1

SelectLists 클래스는 자신을 인스턴스화하는 대신 IReferenceDataManager을 삽입 할 수 있도록 리팩터링되어야합니다.

+0

나는 이것을 시도하고 내가 더 이상 얻을 수 있는지 알아보기 위해 – jazza1000

+0

만약 내가 당신이라면 정적 클래스가 아니고 컨트롤러에 인스턴스가있는 'SelectList'를 만드는 것에 대해 진지하게 생각할 것입니다. 당신은 의존성 주입을 사용해야한다. ASP.NET MVC 4는이를 잘 지원합니다. http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4- dependency-injection –