модульное тестирование свойств c # - PullRequest
9 голосов
/ 04 мая 2011

Я работаю с классом, у которого много свойств. Например;

public class Bib
{        
    public int PartQty { get; set; }
}

Теперь к юнит-тесту; Я сделал тест xUnit что-то вроде

    [Fact]
    public void CanGetAndSetPartQuantity()
    {
        const int expected = 3;

        var target = new Bib() {PartQty = expected};

        Assert.Equal(expected, target.PartQty);
    }

здесь, я ненавижу то, что я ожидаю жесткого кодирования = 3. Какой хороший способ проверить это свойство на предмет доступа и мутатора?

Ответы [ 8 ]

14 голосов
/ 04 мая 2011

Так как это свойство не имеет никакого поведения, кроме того, чтобы быть получателем / установщиком для целого числа, вы просто проверяете, что компилятор работал. Это практически не добавляет ценности вашему тесту. Рассмотрите удаление этого полностью. Это облегчит вам эту странную ситуацию. :)

Если у вас есть какое-то поведение, которое вы пытаетесь уловить (например, допустимые граничные условия), вам нужно только протестировать их, и в действительности ничего больше. Обычно у вас будут константы для этих граничных условий, доступных как часть объекта. Подумайте об использовании этих констант, +/- некоторое соответствующее приращение.

8 голосов
/ 04 мая 2011

Ограниченный недетерминизм хорошо подходит для такого рода модульных тестов.Напишите это так:

[Fact]
public void CanGetAndSetPartQuantity()
{
    const int expected = new Random().Next();

    var target = new Bib() {PartQty = expected};

    Assert.Equal(expected, target.PartQty);
}

Это гарантирует, что вывод правильно представляет вход, независимо от того, какой вход.

6 голосов
/ 04 мая 2011

Я твердо верю в то, что юнит-тесты должны быть тестами «белого ящика», что означает, что вам разрешено использовать известные угловые случаи для выбора входных данных теста.В этом конкретном случае, с авто-свойством, тест не нужен, если вы доверяете своему компилятору.Если вы не можете доверять компилятору реализовать авто-свойство так, как вы ожидаете, то вы не можете доверять ему и выполнение теста в том виде, как вы написали.

При этом, если у вас естьболее сложный установщик, вы бы выбрали свои входы на основе возможных случаев отказа.Несколько типичных случаев:

  • Отрицательные числа для свойств, которые проверяют> = 0
  • Другие ошибки проверки
  • Экстремальные граничные случаи, такие как Int.MaxValue, которые иногда могут вызывать переполненияи неожиданное поведение в установщике
  • Произвольное значение, которое должно пройти проверку (никаких реальных указаний о том, как выбрать значение здесь, если вы знаете, что оно в вашем "хорошем" случае.)
2 голосов
/ 24 апреля 2012

Хотя я также считаю, что это подпадает под категорию «Тест до скуки», если вы действительно чувствуете, что это стоит попробовать, тесты на одобрение предлагают очень простой способ тестирования.В приложении приведен простой тест для проверки свойств.

[TestMethod]
[UseReporter(typeof(DiffReporter))]
public void TestMethod1()
{
    var fred = new Person{
            Age = 35,
        FirstName = "fred",
        LastName = "Flintstone",
        Hair = Color.Black
           };
    Approvals.Verify(fred.WritePropertiesToString());
}

В результате будет создан файл со следующим текстом:

Person
{
    Age: 35
    FirstName: fred
    LastName: Flintstone
    Hair: Color [Black]
}

Просто переименуйте этот файл в .approved, и все готово.

Обратите внимание на использование метода расширения: .WritePropertiesToString ()

Здесь есть видео об основах тестов на утверждение для

MsTest: http://www.youtube.com/watch?v=bg8GOmlwqYY

Nunit: http://www.youtube.com/watch?v=aO_fyZBxaFk

Xunit: http://www.youtube.com/watch?v=8wPx0O4gFzc

2 голосов
/ 04 мая 2011

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

Вариант использования информирует тест, который сообщает код. Я очень сомневаюсь, что ваш вариант использования таков: «пользователь моего API может установить свойство с именем PartQty для любого целого числа и всегда получить обратно целое число, которое он установил». Если бы это был реальный вариант использования, вы бы написали модульный тест, который проверяет int.MaxValue и int.MinValue. Тем не менее, это редко реальные ценности.

Реальный сценарий использования может выглядеть следующим образом: "пользователь моих новостей API вводит Bib, вводя IFlugleBinder, устанавливает PartQty в 4 и затем вызывает метод Execute. Это вызывает Bind метод на экземпляре IFlugleBinder 4 раза. " Если бы это был вариант использования, ваш тест выглядел бы совсем иначе.

Честно говоря, похоже, что Bib это просто DTO какого-то рода. По моему опыту, большинство DTO - просто артефакт некоторого варианта использования более высокого уровня. Если DTO возвращается как результат вызова функции, предоставляемого вашим API, тогда вы действительно должны возвращать интерфейс, а сам класс DTO должен быть закрытым, и в этом случае нет необходимости тестировать его явно (просто протестируйте свойства фактического результата, который вы получаете от вызова метода). Точно так же, если это внутренний DTO, который никогда не раскрывается, тогда не делайте его публичным. Если ваш пользователь должен предоставить некоторый набор значений, то ваш API должен принимать интерфейс. Пусть пользователь определит свой собственный класс, который реализует интерфейс, или предоставит неизменный класс, например:

public class Bib : IBib
{
    public Bib(int partQty)
    {
        PartQty = partQty;
    }
    public int PartQty { get; private set; }
}

Затем вы можете написать тест, который проверяет, работает ли ваш конструктор, если вы хотите быть педантичным, но это не так важно.

2 голосов
/ 04 мая 2011

Я видел презентацию о хороших методах модульного тестирования некоторое время назад (извините, но имя парня ускользнуло от моей хрупкой памяти). Он выступал за использование таких значений в константах с тщательно подобранными именами.

В вашем случае я бы использовал имя типа

const int SomeRandomValidPartQuantity=3;

Этим вы сигнализируете о намерении использовать именно это значение, и в этом случае вы просто набираете любое действительное количество.

2 голосов
/ 04 мая 2011

Это должно помочь ...

[Fact]     
public void CanGetAndSetPartQuantity()     
{
    bool fail = false;
    int expected = 0;

    while (!fail && expected < int.MaxValue)
    {
        var target = new Bib() {PartQty = expected};          
        fail = expected != target.PartQty;
        expected++;
    }

    Assert.IsTrue(!fail);
} 
0 голосов
/ 28 августа 2018

также вы можете использовать атрибут autofixture autodata, например:

        [Theory]
        [AutoData]
        public void CanGetAndSetPartQuantity(int expected)
        {
            var target = new Bib() {PartQty = expected};

            Assert.Equal(expected, target.PartQty);
        }
...