2015-10-13 3 views
2

Я работал над созданием некоторых модульных тестов для своих ViewModels в моем проекте. У меня действительно не было проблем, поскольку большинство из них были очень простыми, но столкнулся с проблемой, когда у меня появился новый (незавершенный) ViewModel внутри другого моего ViewModel.Что вы должны делать с вложенными ViewModels при модульном тестировании?

public class OrderViewModel : ViewModelBase 
{ 
    public OrderViewModel(IDataService dataService, int orderId) 
    { 
     \\ ... 

     Payments = new ObservableCollection<PaymentViewModel>(); 
    } 

    public ObservableCollection<PaymentViewModel> Payments { get; private set; } 

    public OrderStatus Status { ... } //INPC 

    public void AddPayment() 
    { 
     var vm = new PaymentViewModel(); 

     payments.Add(vm); 

     // TODO: Subscribe to PaymentViewModel.OnPropertyChanged so that 
     // if the payment is valid, we update the Status to ready. 
    } 
} 

Я хочу, чтобы создать модульный тест, так что если какой-либо из моих PaymentViewModel «ы IsValid изменения собственности и все из них правда, что Status должны быть OrderStatus.Ready. Я могу реализовать класс, но меня беспокоит то, что мой модульный тест сломается, если проблема в PaymentViewModel.

Я не уверен, что это нормально или нет, но мне кажется, что мне не нужно беспокоиться о том, правильно ли работает PaymentViewModel, для того чтобы мой модульный тест для OrderViewModel был верным.

public void GivenPaymentIsValidChangesAndAllPaymentsAreValid_ThenStatusIsReady() 
{ 
    var vm = new OrderViewModel(); 

    vm.AddPayment(); 
    vm.AddPayment(); 

    foreach (var payment in vm.Payments) 
    { 
     Assert.AreNotEqual(vm.Status, OrderStatus.Ready); 

     MakePaymentValid(payment); 
    } 

    // Now all payments should be valid, so the order status should be ready. 
    Assert.AreEqual(vm.Status, OrderStatus.Ready); 
} 

Проблема в том, как я пишу MakePaymentValid таким образом, что я гарантирую, что поведение PaymentViewModel не будет отрицательно влиять на мое модульное тестирование? Потому что, если это так, то мой модульный тест завершится неудачно, поскольку другой фрагмент кода не работает, а не мой код. Или, если он не сработает, если PaymentViewModel ошибочен? Я просто разорван тем, что не думаю, что мои тесты для OrderViewModel не сработают, если у PaymentViewModel есть ошибка.

Я понимаю, что всегда мог создать интерфейс, например, как я делаю с IDataService, но мне кажется, что это немного лишний, чтобы каждый из ViewModel имел интерфейс и вводил в какой-то форме?

+0

Если я правильно понял вас. Вы можете создать отдельный тест для PaymentViewModel, если есть что-то, что может потенциально прервать, связанное с свойством IsValid в PaymentViewModel, оставив его неповрежденным. С другой стороны, если IsValid - простой сеттер без какой-либо бизнес-логики, то вы бы тестировали ObservableCollection по существу, создав отдельный тест, который, кажется, избыточен. –

ответ

3

Когда дело доходит до модульного тестирования, вы абсолютно должны отделять свои тесты от любых внешних зависимостей. Имейте в виду, что это не означает, что вы должны пройти в каком-то интерфейсе; вы столкнетесь с ситуациями, в которых вы используете определенный класс, независимо от того, входит ли этот класс в ваш контроль или нет.

Представьте, что вместо вашего примера вы полагались на DateTime.Now. Некоторые из них возражают, чтобы отвлечь его на какой-то интерфейс IDateTimeService, который мог бы работать. Кроме того, вы можете воспользоваться Microsoft Fakes: Shims & Stubs.

Microsoft Fakes позволит вам создавать экземпляры Shim *. На эту тему многое предстоит обсудить, но изображение Microsoft показывает, что использование подделок выходит за пределы классов из-под вашего контроля (в том числе и компоненты, входящие в ваш контроль).

Microsoft Fakes Shims/Stubs

Обратите внимание, как компонент тестируется (OrderViewModel) должны быть изолированы от System.dll (т.е. DateTime.Now), другие компоненты (PaymentViewModel) и внешних элементов, а также (если вы полагались на базы данных или Веб-сервис). Shim предназначен для фальсификации классов, тогда как Stub предназначен для фальсификации (издевательств) интерфейсов.


После добавления Подделки сборки, просто используйте ShimPaymentViewModel класс, реализующий поведение вы ожидаете, что он должен. Если по какой-либо причине реальная ошибка PaymentViewModel и ваша сбой приложений, вы можете хотя бы быть уверены, что проблема не из-за OrderViewModel. Конечно, чтобы избежать этого, вы должны включить некоторые модульные тесты для PaymentViewModel, чтобы убедиться, что он ведет себя правильно, независимо от того, какие другие классы используют его или как они его используют.

TL; DR;

Да, полностью изолируйте свой компонент, когда дело доходит до тестирования, воспользовавшись Microsoft Fake. О, и Microsoft Fakes отлично играет с другими фреймворками, поэтому не чувствуйте себя так, используя это, чтобы вы отказались от других вариантов; он работает совместно с другими структурами.

Смежные вопросы