بعد استخدام Automapper لرسم خريطة ViewModel كيف وماذا يجب أن أختبر؟

StackOverflow https://stackoverflow.com/questions/3082179

سؤال

أحاول اختبار Index عمل وحدة تحكم. يستخدم العمل السيارات لرسم خريطة مجال Customer اعترض على نموذج العرض TestCustomerForm. بينما يعمل هذا الأمر ، أشعر بالقلق إزاء أفضل طريقة لاختبار النتائج التي أتلقاها من Index عمل.

يبدو أن إجراء فهرس وحدة التحكم مثل هذا:

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

    return View(cust);
}

و TestMethod يشبه هذا:

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

في ال CreateTestController الطريقة التي أستخدمها Rhino.Mocks للسخرية من مستودع العملاء وإعداده لإعادة العميل من SetupCustomerForRepository. وبهذه الطريقة أعلم أن المستودع سيعيد العميل المقصود عند Index مكالمات العمل _repository.GetCustomerByLogin(CurrentUserLoginName). لذلك ، أنا أؤكد أن عدد متساوٍ مناسب للإرضاء IndexShouldReturnCustomerWithMachines.

كل ذلك قيل إنني قلق بشأن ما يجب أن أختبره.

  1. يبدو من المفترض أن نلقي result.ViewData.Model as TestCustomerForm. هل هذه حقا مشكلة؟ هذا يهمني لأنني في هذه الحالة لا أقوم حقًا بتطوير الاختبار ويبدو أنني أعتمد على تطبيق معين لتلبية الاختبار.
  2. هل هناك اختبارات أكثر ملاءمة لضمان الخرائط الصحيحة؟
  3. هل يجب أن أختبر كل خاصية تم تعيينها من TestCustomerForm?
  4. هل هناك اختبارات عمل تحكم أكثر عمومية يجب أن أقوم بها؟
هل كانت مفيدة؟

المحلول

هذا هو أحد الأسباب التي تجعلنا ننقل السيارات إلى ActionResult أو ActionFilter. في مرحلة ما ، تريد فقط اختبار أنك قمت بتعيين Foo إلى Foodto ، ولكن ليس بالضرورة اختبار الخرائط الفعلية. من خلال نقل السيارات إلى حدود الطبقة (مثل عرض وحدة التحكم) ، يمكنك مجرد اختبار ما تخبره بالسيارات للقيام به.

هذا مشابه للاختبار ViewResult. لا تختبر من وحدة تحكم تم تقديم طريقة عرض ، بل كنت قد أخبرت MVC تقديم مثل هذا العرض. تصبح نتيجة عملنا:

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

مع طريقة مساعد على فئة وحدة تحكم قاعدة:

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

الأمر الذي يجعل وحدة التحكم الآن الآن تحدد فقط ما يجب تعيينه من/من/إلى ، بدلاً من تنفيذ التعيين الفعلي:

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

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

في هذه المرحلة ، أحتاج فقط إلى الاختبار ، "تأكد من قيامك بتخطيط كائن FOO هذا إلى هذا النوع من Foodto Destination" ، دون الحاجة إلى أداء التعيين بالفعل.

تعديل:

إليك مثال على مقتطف الاختبار:

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

نصائح أخرى

من المحتمل أن أفصل الاقتران بين AutoMapper ووحدة التحكم عن طريق إدخال تجريد:

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

بعد ذلك ، تقوم بتمرير هذا إلى وحدة التحكم:

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

وفي اختبار الوحدة الخاص بك ، يمكنك استخدام إطار السخرية المفضل لديك لاستنباط هذا الخريطة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top