Модульное тестирование Viewmodel - PullRequest
12 голосов
/ 30 января 2011

Я новичок в TDD. Я начал создавать нужные мне свойства модели представления как обычное автоматическое свойство.

public string Firstname { get; set; }

Тогда я создаю тест

[TestMethod]
[Tag("Property")]
public void FirstNameTest()
{
    ViewModel = new CustomerViewModel();
    ViewModel.PropertyChanged += (s, e) =>
                                     {
                                         Assert.AreEqual("Firstname", e.PropertyName);
                                         Assert.AreEqual("Test", ViewModel.Firstname);
                                     };
    ViewModel.Firstname = "Test";
}

Тогда я бы расширил фактическую реализацию так, чтобы тест проходил так:

public string Firstname
{
    get { return _contact.FirstName; }
    set
    {
        if (_contact.FirstName == value)
            return;

        _contact.FirstName = value;

        RaisePropertyChanged(() => Firstname);
    }
}

У меня проблема в том, что тест все еще проходит для свойства Aut. Любой совет для меня, как я мог бы улучшить свой процесс?

Ответы [ 6 ]

10 голосов
/ 31 января 2011

Вы можете сделать что-то вроде этого:

    [TestMethod]
    [Tag("Property")]
    public void FirstNameTest()
    {
        bool didFire = false;
        ViewModel = new CustomerViewModel();
        ViewModel.PropertyChanged += (s, e) =>
                                         {
                                             didFire = true;
                                             Assert.AreEqual("Firstname", e.PropertyName);
                                             Assert.AreEqual("Test", ViewModel.Firstname);
                                         };
        ViewModel.Firstname = "Test";
        Assert.IsTrue(didFire);
    }
7 голосов
/ 31 января 2011

Вы можете попробовать написать тест асинхронным.Рассмотрим этот метод тестирования:

[TestMethod]
[Asynchronous]
public void TestMethod1()
{
    TestViewModel testViewModel = new TestViewModel();

    bool firstNameChanged = false;

    testViewModel.PropertyChanged +=
        (s, e) =>
            {
                if (e.PropertyName == "FirstName")
                {
                    firstNameChanged = true;
                }
            };

    EnqueueCallback(() => testViewModel.FirstName = "first name");
    EnqueueConditional(() => firstNameChanged == true);
    EnqueueTestComplete();
}

Обратите внимание на асинхронный атрибут в верхней части метода.Здесь есть два важных метода: EnqueueCallback и EnqueueTestComplete.EnqueueCallback добавит лямбда-выражения в очередь, а тестовый метод будет ожидать выполнения текущего обратного вызова.В данном случае мы подписываемся на событие PropertyChanged в ViewModel и устанавливаем для локальной логической переменной значение true, когда свойство FirstName уведомляет об изменении.Затем мы ставим в очередь два обратных вызова: один для установки свойства FirstName и один для подтверждения того, что локальная логическая переменная изменила значение.Наконец, нам нужно добавить вызов EnqueueTestComplete (), чтобы инфраструктура знала, что тест закончен.

ПРИМЕЧАНИЕ. Чтобы получить EnqueueCallback и EnqueueTestComplete, вам необходимо наследовать от SilverlightTest в своем классе тестирования.Вам также необходимо импортировать Microsoft.Silverlight.Testing, чтобы получить асинхронный атрибут.Это должно выглядеть примерно так:

using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Foo.Example.Test
{
    [TestClass]
    public class Tests : SilverlightTest
    {

        // ... tests go here
    }
}
2 голосов
/ 31 января 2011

Тест должен провалиться, если только тестируемое поведение уже не реализовано.

Для тестирования уведомлений об изменениях свойств в моей последней попытке я создал вспомогательный класс , который помог мне написать такие тесты (это в NUnit)

[Test]
public void NotifiesChangeIn_TogglePauseTooltip()
{
   var listener = new PropertyChangeListener(_mainViewModel);

   _mainViewModel.TogglePauseCommand.Execute(null);

   Assert.That(listener.HasReceivedChangeNotificationFor("TogglePauseTooltip"));
}
2 голосов
/ 30 января 2011

Вам нужен еще один тест, который фактически подтверждает, что ваш PropertyChanged даже срабатывает.

При выполнении этого теста ваше свойство auto должно завершиться ошибкой, поскольку событие никогда не сработает.

Вот пример того, как это сделать в Moq

1 голос
/ 31 января 2011

Вот как я делал это в прошлом (я использовал NUnit, поэтому он может немного отличаться):

[Test]
public void ShouldNotifyListenersWhenFirstNameChanges()
{
    var propertiesChanged = new List<string>();

    ViewModel = new CustomerViewModel();
    ViewModel.PropertyChanged += (s, e) => propertiesChanged.Add(e.PropertyName);

    ViewModel.Firstname = "Test";

    Assert.Contains("Firstname", propertiesChanged);      
    Assert.AreEqual("Test", ViewModel.Firstname);  
}

Имеет приятный побочный эффект, заключающийся в возможности отладки и обработки того, что изменилось, если бы не было Firstname. Очень удобно, когда у вас есть несколько полей, вычисляемых из других полей. Вы также можете посмотреть на другой аспект поведения в вашем коде:

[Test]
public void ShouldNotNotifyListenersWhenPropertiesAreNotChanged()
{
    var propertiesChanged = new List<string>();

    ViewModel = new CustomerViewModel();
    ViewModel.Firstname = "Test";

    ViewModel.PropertyChanged += (s, e) => propertiesChanged.Add(e.PropertyName);

    ViewModel.Firstname = "Test";

    Assert.AreEqual(0, propertiesChanged.Count); 
}
0 голосов
/ 16 апреля 2014

Возможно, есть еще фон для этого кода, который не раскрывается, но то, что я вижу, кажется излишне сложным.Зачем вообще подключаться к событию RaisePropertyChanged?Просто проверьте свойство после его установки.

[TestMethod]
[Tag("Property")]
public void FirstNameTest()
{
    var expected = "John";
    var sut = new CustomerViewModel();

    sut.Firstname = expected;

    Assert.AreEqual(expected, sut.Firstname);
}

Это также превращает тест в настоящий модульный тест.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...