Как протестировать некоторый метод из этого интерфейса с помощью 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 },
};
Более сложные примеры
Если ваши реализацииони больше отличаются друг от друга, чем это, или вы не можете создать простую матрицу ввода / вывода, вам будет сложнее.
Один из вариантов - вводить делегатов в ваш тестовый пример.Но это так же сложно, непонятно и трудно поддерживать, как кажется.В таком случае вам действительно лучше написать отдельные методы модульного тестирования.