2010-06-21 12 views
11

Bir denetleyicinin Index eylemini denemeye çalışıyorum. Eylem, Customer etki alanını bir görünüm modeline TestCustomerForm eşlemek için AutoMapper kullanır. Bu çalışırken, Index eyleminden aldığım sonuçları sınamanın en iyi yolu konusunda endişeliyim.Bir ViewModel'i eşlemek için Automapper'ı kullandıktan sonra nasıl ve ne test etmeliyim?

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

    return View(cust); 
} 

Ve TestMethod şuna benzer::

kontrolörün endeksi eylemi şöyle bir müşteri depo alay ve bunu kurmak için Rhino.Mocks kullanmak CreateTestController yöntemde

[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()); 
} 

müşteriyi SetupCustomerForRepository'dan iade edin. Bu şekilde, havuzun, hedeflenen müşteriyi Index eylemi _repository.GetCustomerByLogin(CurrentUserLoginName) çağırdığında iade edeceğini biliyorum. Bu nedenle, eşit bir sayımın IndexShouldReturnCustomerWithMachines'u tatmin etmek için yeterli olduğunu iddia ediyorum.

Bunların hepsi, test etmem gereken şey konusunda endişeliyim dedi.

  1. result.ViewData.Model as TestCustomerForm'u dökmek tahminsiz görünüyor. Bu gerçekten bir sorun mu? Bu durum beni endişelendiriyor çünkü bu durumda gerçekten test odaklı gelişim yapıyorum ve testi tatmin etmek için belirli bir uygulamaya güveniyorum gibi görünüyor.
  2. Doğru haritalamayı sağlamak için daha uygun testler var mı?
  3. Her eşlenen özelliği TestCustomerForm'dan mı test etmeliyim?
  4. Yapmam gereken daha genel denetleyici eylem testleri var mı? Eğer denetleyici içine bu geçiş

    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); 
        } 
    } 
    

    Sonraki:

cevap

15

Bu, AutoMapper'ı özel bir ActionResult veya ActionFilter'e taşımamızın nedenlerinden biridir. Bir noktada, sadece Foo'yu FooDto'ya eşlediğinizi test etmek istersiniz, ancak gerçek haritalamayı mutlaka test etmenize gerek yoktur. AutoMapper'ı katman sınırlarına getirerek (denetleyici arasında bir görünüm gibi), sadece AutoMapper'ın yapmasını istediklerinizi test edebilirsiniz.

Bu, ViewResult'un test edilmesine benzer. Bir denetleyiciden görüntünün oluşturulduğunu test etmiyorsunuz, bunun yerine MVC'ye bu türden bir görünüm oluşturmasını söylediniz.Bizim eylem sonucu olur: bir taban kontrolör sınıfı bir yardımcı yöntemle

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); 
    } 
} 

: o zaman kontrolör yapar

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

şimdi sadece yerine gerçek eşleme gerçekleştirme,/dan harita ne belirtmek :

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

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

, ben sadece aslında MAPPI gerçekleştirmek için gerek kalmadan, "Bu hedef FooDto tipine bu Foo nesnesi haritalama emin olun", test etmek gerekir ng.

DÜZENLEME:

Burada bir deney pasajının bir örnek verilmiştir:

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

Çok anlamlı olan büyük cevap. Kuşak için test ifadenizi ekleyebilir misiniz? – ahsteele

+1

Bu, Get Me yönteminin bir IEnumerable döndürdüğü ve bir eylem sonucu olmayan yeni WebApi ile nasıl çalışır? – shashi

+0

@sassyboy Ben kendinize benzer bir soyutlama yaratabileceğiniz, web api ile izole bir hizmet katmanı kullanma eğilimindeyim. –

2

muhtemelen AutoMapper arasındaki bağlantı ve bir soyutlama tanıtarak kontrolörü ayırmak istiyorum

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); 
    } 
} 

Ve birim testinde sen En sevdiğiniz alay çerçevesini bu eşleştiriciyi yerleştirmek için kullanırdım.

+0

Bu testler değerinin düşük ucunda bulunmaktadır. AutoMapper ile tam olarak ne test ettiğinizi söylerseniz, bu Harita aranır mı? Akış mantığı vb. Yoktur. Sadece daha yüksek test kapsamı sağlar. Denetleyicileriniz o kadar ince (karmaşıklık bağlayıcılara, filtrelere, eylem başlatıcılarına vb.) Taşındığında, o zaman sadece "Birim" test etmeyin (alev bekler) –

+0

@mattcodes, bu denetleyici eylemi test edilmesi gereken üç şeyi yapar: bir depo kullanır (alay!), bu deponun sonucu başka bir türe eşlenir (alay!), eşlemenin sonucu görünümüne döndürülür. Bu havuzun verileri getirdiği ve eşlemenin nasıl gerçekleştirildiği, denetleyiciye düşük değerde olduğu ve ayrı olarak test edilmesi gerektiğinde. Tabii ki bir alternatif olarak, bu eylemin test edilmesine gerek olmadığını söyleyebiliriz ancak OP'lerin sorusu tam olarak birim testi ile ilgiliydi, bu yüzden iki sentimi verdim :-) –