Вопрос

Мне интересно, как кому-то следует использовать Assert.Inconclusive().

Я использую его, если мой модульный тест может провалиться по причине, отличной от цели теста.

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

Написать модульный тест для Sum() очень просто.Однако, когда я пишу тест для Average() и Sum() терпит неудачу, то и Average(), скорее всего, также потерпит неудачу.

Причина неудачи Average не указана явно;он потерпел неудачу по причине, отличной от той, по которой он должен проверяться.Вот почему я бы проверил, возвращает ли Sum() правильный результат, иначе я Assert.Inconclusive().

Можно ли считать это хорошей практикой?Для чего предназначен Assert.Inconclusive?Или мне лучше решить предыдущий пример с помощью Isolation Framework?

Это было полезно?

Решение

Когда я использую VS для создания модульных тестов, я получил Assert.Inclusive для сгенерированных методов тестирования, и обычно я меняю утверждение на что-то еще, когда работаю с ними.Я использую вопросительные знаки Assert.Inconclusive в результатах теста в качестве маркеров, позволяющих быстро определить, какие тесты я еще не завершил.

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

Однако, судя по описанию вашего Average() метод, я думаю, что, возможно, ваш модульный тест недостаточно атомарен, чтобы охватить только один «модуль», один конкретный сценарий.Иногда я пишу 2 или 3 метода модульного тестирования для одного метода.Или ты можешь сломать свой Average() метод к более мелким методам, охватывающим отдельные обязанности.Таким образом, вы можете протестировать эти более мелкие методы перед модульным тестированием. Average() один.


Йоханнес,

Вот как я бы реализовал Sum() и Average() методы.

public static class MyMath
{
    private static void ValidateInput(ICollection<int> numbers)
    {
        if (numbers == null)
            throw new ArgumentNullException("numbers", "Null input.  Nothing to compute!");
        if (numbers.Count == 0)
            throw new ArgumentException("Input is empty.  Nothing to compute!");
    }

    public static int Sum(int[] numbers)
    {
        ValidateInput(numbers);

        var total = 0;
        foreach (var number in numbers)
            total += number;

        return total;
    }

    public static double Average(int[] numbers)
    {
        ValidateInput(numbers);
        return Sum(numbers) / numbers.Length;
    }
}

Для простоты я просто кидаю ArgumentException исключения из ValidateInput(ICollection<int>) метод.Вы также можете проверить возможность переполнения и выброса OverflowException в ValidateInput(ICollection<int>) метод.

С учетом вышесказанного, вот как я бы протестировал Average(int[]) функция.

[TestMethod]
public void AverageTest_GoodInput()
{
    int[] numbers = {1, 2, 3};
    const double expected = 2.0;
    var actual = MyMath.Average(numbers);
    Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void AverageTest_NullInput()
{
    int[] numbers = null;
    MyMath.Average(numbers);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void AverageTest_EmptyInput()
{
    var numbers = new int[0];
    MyMath.Average(numbers);
}

Благодаря настройке этих тестов я могу быть уверен, что, когда все тесты пройдут успешно, моя функция будет правильной.Ну, кроме случая переполнения.Теперь я могу вернуться в ValidateInput(ICollection<int>) метод, чтобы добавить логику для проверки переполнения, затем добавьте еще один тест, чтобы ожидать OverflowException выбрасываться для тех входных данных, которые вызывают переполнение.Или сделайте это в обратном порядке, если вам нравится использовать TDD.

Надеюсь, это поможет прояснить идею.

Другие советы

Неокончательный тест - это тест, для которого вы не можете определить результат. Например, что если у вас есть тест, который использует какой-то внешний ресурс (например, подключение к Интернету). Если соединение в данный момент недоступно, это не значит, что тест не пройден. С другой стороны, вы не должны просто пометить его как успешный, не выполнив его. Таким образом, вы помечаете его как неокончательный, и это можно увидеть в протоколе испытаний.

ПРИМЕЧАНИЕ. В целом, вы не должны использовать такие внешние ресурсы в своих тестах, так как это может сделать тесты хрупкими.

Для тестов, которые еще не были завершены, я использую атрибут Explicit MbUnit.

Я только Assert.Incclusive на модульных тестах я еще не написал. Иногда, когда я пишу что-то, я понимаю какой-то угловой случай, который я не хочу пропустить. Поэтому я быстро перепрыгиваю, пишу тестовый метод с описательным именем и добавляю одну строку Assert.Inconclusive.

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

Assert.Inconclusive указывает, что либо:

Я еще не написал тест; я только создал тестовый метод

-или-

У моего теста есть зависимость, и эта зависимость недоступна.Например

List<Customer> custs = o.GetAllCustomers();
if (custs.Count == 0)
{
  Assert.Inconclusive("No customers to test");
  return;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top