Как тестировать разные классы с одним интерфейсом? - PullRequest
4 голосов
/ 05 ноября 2011

У меня есть интерфейс ISome. есть 4 класса, такие как MyClass1: ISome, MyClass2: ISome и т. д. Как протестировать какой-либо метод из этого интерфейса с помощью NUnit, но сделать только 1 юнит-тест для всех классов?

Ответы [ 5 ]

4 голосов
/ 05 ноября 2011

4 класса означает 4 различных реализации данного метода.Как следствие у вас должно быть 4 модульных теста.Было бы неправильно пытаться написать отдельный модульный тест.

3 голосов
/ 06 ноября 2011

Как протестировать некоторый метод из этого интерфейса с помощью NUnit, но сделать только 1 юнит-тест для всех классов?

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

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

Таким образом, вы сталкиваетесь с одним вариантом: Вам необходимо несколько модульных тестов .

Дублирование кода

Для избегатьДублируя ваш код модульного теста , вы можете попробовать параметризованные функции модульного теста NUnit.

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

Существует множество способов параметризации ваших тестов в NUnit.Смотрите эту статью:

Я лично предпочитаю атрибут TestCaseSource:

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

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

Как параметризовать реализацию

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

Impl      Input1  Input2  Result
Multiply  0       7       0
Multiply  3       6       18
Add       0       0       0
Add       5       6       11

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

Вот пример кода, который реализует эти операции:

// This interface takes two ints, returns one int
public interface IBinaryOperation
{
    int Execute(int x, int y);
    string Name { get; }
}

public class Add : IBinaryOperation
{
    public int Execute(int x, int y) { return x + y; }
    public string Name { get { return "Add"; } }
}

public class Multiply : IBinaryOperation
{
    public int Execute(int x, int y) { return x * y; }
    public string Name { get { return "Multiply"; } }
}

А вот пример реализации тестового устройства:

[Test, TestCaseSource("OperationTestCases")]
public void ExecuteReturnsCorrectResult(
    IBinaryOperation operation,
    int inputX, int inputY,
    int expectedResult
    )
{
    int actualResult = operation.Execute(inputX, inputY);
    Assert.That(actualResult, Is.EqualTo(expectedResult),
        "Expected operation: '{0}', with '{1}' and '{2}' to return '{3}'"
        , operation.Name
        , inputX
        , inputY
        , expectedResult
        );
}

static object[] OperationTestCases =
{
    new object[] { new Multiply(), 0, 7, 0 },
    new object[] { new Multiply(), 3, 6, 18 },
    new object[] { new Add(), 0, 0, 0 },
    new object[] { new Add(), 5, 6, 11 },
};

Results from running this test suite in NUnit

Более сложные примеры

Если ваши реализацииони больше отличаются друг от друга, чем это, или вы не можете создать простую матрицу ввода / вывода, вам будет сложнее.

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

2 голосов
/ 05 ноября 2011

Дарин Димитров, как правило, прав, но вы можете для удобства реализовать один абстрактный контрольный пример для всех реализаций.Работая с абстрактным методом, таким как

protected abstract ISome createInstance();

, и переопределяя его в тестовых примерах, наследуя от вашего абстрактного тестового класса, будет работать.

1 голос
/ 05 ноября 2011

Вы можете проверить плагин NUnit интерфейса Greg Young: https://github.com/gregoryyoung/grensesnitt

0 голосов
/ 05 ноября 2011

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

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