2010-06-21 13 views
11

Tôi đang cố gắng kiểm tra hành động Index của bộ điều khiển. Hành động sử dụng AutoMapper để ánh xạ miền đối tượng Customer đến kiểu xem TestCustomerForm. Trong khi công trình này tôi quan tâm về cách tốt nhất để kiểm tra các kết quả mà tôi nhận được từ hành động Index.Sau khi sử dụng Automapper để ánh xạ một ViewModel như thế nào và những gì tôi nên kiểm tra?

action index của bộ điều khiển trông như thế này:

public ActionResult Index() 
{ 
    TestCustomerForm cust = Mapper.Map<Customer, 
     TestCustomerForm>(_repository.GetCustomerByLogin(CurrentUserLoginName)); 

    return View(cust); 
} 

TestMethod của nó trông như thế này:

[TestMethod] 
public void IndexShouldReturnCustomerWithMachines() 
{ 
    // arrange 
    var customer = SetupCustomerForRepository(); // gets a boiler plate customer 
    var testController = CreateTestController(); 

    // act 
    ViewResult result = testController.Index() as ViewResult; 

    // assert 
    Assert.AreEqual(customer.MachineList.Count(), 
     (result.ViewData.Model as TestCustomerForm).MachineList.Count()); 
} 

Trong CreateTestController phương pháp tôi sử dụng Rhino.Mocks để thử một kho lưu trữ của khách hàng và thiết lập nó để trả lại khách hàng từ SetupCustomerForRepository. Theo cách này, tôi biết rằng kho lưu trữ sẽ trả về khách hàng dự định khi các cuộc gọi hành động Index_repository.GetCustomerByLogin(CurrentUserLoginName). Do đó, con số xác nhận số lượng bằng nhau là đủ để đáp ứng IndexShouldReturnCustomerWithMachines.

Tất cả điều đó đều nói rằng tôi quan tâm đến những gì tôi nên thử nghiệm.

  1. Dường như có ý định đúc result.ViewData.Model as TestCustomerForm. Đây thực sự là một vấn đề? Điều này liên quan đến tôi bởi vì trong trường hợp này tôi không thực sự làm phát triển thử nghiệm theo định hướng và có vẻ như tôi đang dựa vào một triển khai cụ thể để đáp ứng bài kiểm tra.
  2. Có thử nghiệm phù hợp hơn để đảm bảo ánh xạ chính xác không?
  3. Tôi có nên kiểm tra từng thuộc tính được ánh xạ từ TestCustomerForm không?
  4. Có thử nghiệm hành động điều khiển tổng quát nào khác mà tôi nên thực hiện không?

Trả lời

15

Đây là một trong những lý do tại sao chúng tôi di chuyển AutoMapper vào ActionResult tùy chỉnh hoặc ActionFilter. Tại một số điểm, bạn chỉ thực sự muốn kiểm tra rằng bạn đã ánh xạ Foo tới FooDto, nhưng không nhất thiết phải kiểm tra ánh xạ thực tế. Bằng cách di chuyển AutoMapper vào các ranh giới lớp (chẳng hạn như giữa một bộ điều khiển một khung nhìn), bạn chỉ có thể kiểm tra những gì bạn đang nói với AutoMapper để làm.

Điều này tương tự như việc kiểm tra ViewResult. Bạn không kiểm tra từ một bộ điều khiển mà một khung nhìn đã được hiển thị, nhưng đúng hơn là bạn đã nói với MVC để hiển thị chế độ xem như vậy.kết quả hành động của chúng tôi trở thành:

public class AutoMapViewResult : ActionResult 
{ 
    public Type SourceType { get; private set; } 
    public Type DestinationType { get; private set; } 
    public ViewResult View { get; private set; } 

    public AutoMapViewResult(Type sourceType, Type destinationType, ViewResult view) 
    { 
     SourceType = sourceType; 
     DestinationType = destinationType; 
     View = view; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var model = Mapper.Map(View.ViewData.Model, SourceType, DestinationType); 

     View.ViewData.Model = model; 

     View.ExecuteResult(context); 
    } 
} 

Với một phương pháp helper trên một lớp điều khiển cơ bản:

protected AutoMapViewResult AutoMapView<TDestination>(ViewResult viewResult) 
{ 
    return new AutoMapViewResult(viewResult.ViewData.Model.GetType(), typeof(TDestination), viewResult); 
} 

Mà sau đó làm cho bộ điều khiển bây giờ chỉ định để lập bản đồ gì đi/đến, thay vì thực hiện việc lập bản đồ thực tế :

public ActionResult Index(int minSessions = 0) 
{ 
    var list = from conf in _repository.Query() 
       where conf.SessionCount >= minSessions 
       select conf; 

    return AutoMapView<EventListModel[]>(View(list)); 
} 

Tại thời điểm này, tôi chỉ cần kiểm tra "đảm bảo rằng bạn đang ánh xạ đối tượng Foo này đến đích FooDto", mà không cần thực sự thực hiện mappi ng.

EDIT:

Dưới đây là một ví dụ về một đoạn mã kiểm tra:

var actionResult = controller.Index(); 

actionResult.ShouldBeInstanceOf<AutoMapViewResult>(); 

var autoMapViewResult = (AutoMapViewResult) actionResult; 

autoMapViewResult.DestinationType.ShouldEqual(typeof(EventListModel[])); 
autoMapViewResult.View.ViewData.Model.ShouldEqual(queryResult); 
autoMapViewResult.View.ViewName.ShouldEqual(string.Empty); 
+0

Câu trả lời tuyệt vời mà làm cho rất nhiều ý nghĩa. Đối với hậu thế, bạn có muốn thêm câu lệnh kiểm tra của mình không? – ahsteele

+1

Làm cách nào để làm việc với WebApi mới, trong đó phương thức Get của tôi trả về một số không thể truy cập là và không phải là kết quả hành động? – shashi

+0

@sassyboy Tôi có xu hướng sử dụng một lớp dịch vụ riêng biệt với api web, nơi bạn có thể tạo ra một sự trừu tượng tương tự của riêng bạn. –

2

tôi có lẽ sẽ tách các khớp nối giữa AutoMapper và bộ điều khiển bằng cách giới thiệu một sự trừu tượng:

public interface IMapper<TSource, TDest> 
{ 
    TDest Map(TSource source); 
} 

public CustomerToTestCustomerFormMapper: IMapper<Customer, TestCustomerForm> 
{ 
    static CustomerToTestCustomerFormMapper() 
    { 
     // TODO: Configure the mapping rules here 
    } 

    public TestCustomerForm Map(Customer source) 
    { 
     return Mapper.Map<Customer, TestCustomerForm>(source); 
    } 
} 

Tiếp theo, bạn chuyển thông tin này vào bộ điều khiển:

public HomeController: Controller 
{ 
    private readonly IMapper<Customer, TestCustomerForm> _customerMapper; 
    public HomeController(IMapper<Customer, TestCustomerForm> customerMapper) 
    { 
     _customerMapper = customerMapper; 
    } 

    public ActionResult Index() 
    { 
     TestCustomerForm cust = _customerMapper.Map(
      _repository.GetCustomerByLogin(CurrentUserLoginName) 
     ); 
     return View(cust); 
    } 
} 

Và trong thử nghiệm đơn vị của bạn, bạn sẽ sử dụng khung mocking yêu thích của bạn để mở trình ánh xạ này.

+0

Các xét nghiệm này vào cuối thấp của giá trị. Nếu bạn thử AutoMapper chính xác những gì bạn đang thử nghiệm, mà Bản đồ được gọi là? Không có luồng logic, vv .. nó chỉ cho phép có được vùng phủ sóng thử nghiệm cao hơn. Khi bộ điều khiển của bạn mỏng như vậy (độ phức tạp được chuyển đến bộ phận kết dính, bộ lọc, người hút hành động vv ..) thì chỉ cần không "Đơn vị" kiểm tra chúng (chờ đợi ngọn lửa) –

+0

@mattcodes, hành động điều khiển này thực hiện ba điều cần được kiểm tra: sử dụng một kho lưu trữ (giả lập nó!), kết quả của kho lưu trữ này được ánh xạ tới một kiểu khác (giả lập nó!), kết quả của ánh xạ được trả về cho khung nhìn. Trường hợp kho lưu trữ này lấy dữ liệu và cách ánh xạ được thực hiện có giá trị thấp cho bộ điều khiển và cần được kiểm tra riêng. Là một thay thế tất nhiên bạn có thể nói rằng hành động này không cần phải được kiểm tra nhưng câu hỏi OPs là chính xác về thử nghiệm đơn vị vì vậy tôi quyết định cho hai xu của tôi :-) –