Используйте атрибуты теста NUnit для создания входных данных метода

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

И худшее из худшего — это когда ваши коллеги пытаются понять тестовый код, который вы написали 3 месяца назад.

Мне действительно неловко, когда это происходит, особенно потому, что я уважаю их время — самое дорогое, что есть у любого из нас.

В этой статье я расскажу вам о 5 способах использования NUnit Test Framework, чтобы упростить ваш тестовый код и сделать его более читабельным. Я собираюсь сосредоточиться только на входных данных для ваших модульных тестов, а не на самом тесте или правильном способе назвать ваши тесты.

Простой тест для начала

Class1 реализует проверку TrueOnEvenNumbers. Вы можете увидеть повторение с несколькими утверждениями, что совершенно не нужно. Хуже, когда что-то подобное делается в цикле внутри тестового метода.

Наличие одного утверждения для каждого теста облегчает понимание и поддержку тестового кода. Для этого воспользуемся атрибутом NUnit TestCase.

1. Атрибут TestCase

NUnit будет запускать тест один раз для атрибута TestCase. Рефакторинговый тестовый метод теперь принимает входные данные и возвращает выходные данные. Входные данные берутся из первого параметра атрибута TestCase. Вывод проверяется на соответствие свойству ExpectedResult атрибута TestCase. Мне это нравится, так как тест теперь больше фокусируется на проверяемой логике и имеет одно утверждение.

Вывод теста NUnit:

Вывод показывает точное значение параметра, которое передается при каждом вызове метода тестирования.

Логика метода тестирования, используемая здесь, следующая:

  1. Четные числа возвращают true
  2. Числа, которые не являются четными числами, возвращают false

Если вы считаете, что имеет смысл отделить логику, это можно сделать с помощью атрибута Range из NUnit.

2. Атрибут диапазона

Разделив тестовую логику, теперь я проверяю результат ввода четных чисел. Отличный способ сделать это — использовать атрибут Range, который принимает значения «от», «до» и «шаг». .

В этом примере я хочу, чтобы ввод был 40, 42, 44 и 46, и поэтому я использую Range(40, 46, 2), который начинается «с» 40, переходит «к» 46 и увеличивается на каждом 'шаге' на 2. Обратите внимание, что атрибут Range используется во входном параметре, а не в методе тестирования.

Выход:

И тест для нечетных чисел будет выглядеть следующим образом:

Подождите, что это за синтаксис Should().BeFalse()?!

Что ж, это еще один способ сделать ваши тесты более читабельными. Замечательные расширения FluentAssertions позволяют использовать такой свободный синтаксис во время утверждения: https://fluentassertions.com/introduction.

3. Атрибут TestCaseSource

Атрибут TestCase, который мы использовали, позволяет нам также использовать Enumerations:

Для заданного рабочего дня проверьте, соответствует ли настроение человека ожидаемому значению. Обратите внимание на возвращаемый тип метода GetMoodWithReasonForWorkday:

Это не перечисление Mood, а тип MoodWithReason:

Я хотел бы проверить оба свойства структуры MoodWithReason и хотел бы использовать его как свойство ExpectedResult в атрибуте TestCase следующим образом:

Но это приводит к следующей ошибке компиляции:

Не бойтесь, атрибут TestCaseSource здесь:

Атрибут TestCaseSource позволяет нам определить любое количество и тип входных данных (включая ожидаемые результаты) и использовать их в качестве входных данных для наших методов тестирования. Итератор MoodWithReasons (со знаком «s» в конце) определяется следующим образом:

Мы можем получить любое количество TestCaseData элементов из итератора. Тип TestCaseData может принимать любое количество параметров. Мы возвращаем два значения для двух входных параметров нашего тестового метода (Workday workday, MoodWithReason moodWithReason). К сожалению, результаты запуска тестов с нашими сгенерированными параметрами выглядят так:

Второй параметр имеет тип MoodWithReason и не показывает фактические значения, использованные во время теста. Чтобы увидеть фактически переданные параметры, можно использовать другой TestCaseSource:

Соответствующий метод тестирования теперь принимает три входных параметра:

И соответствующий тестовый вывод показывает все значения входных параметров:

4. Атрибут ценности

Атрибут Values создает комбинацию всех возможных входных значений. Давайте посмотрим, что это значит:

Здесь атрибуты Values используются для параметров типа Mood и Reason, каждый из которых является перечислением:

Запуск теста привел к 10 вызовам тестовых методов:

Как видите, NUnit генерирует тест для каждой возможной комбинации двух типов входных параметров!! Как это круто?

Существует несколько атрибутов уровня метода тестирования, которые можно использовать вместе с атрибутом Values для определенных целей. Список всех атрибутов NUnit можно найти по адресу:

https://docs.nunit.org/articles/nunit/writing-tests/attributes.html

5. Атрибут ValueSource

Так же, как атрибут TestCaseSource, есть атрибут ValueSource.

Используя атрибут Values, вы можете написать тест, проверяющий, что любое умножение firstValue и secondValue всегда дает значение меньше 10000. Другой способ сделать это — использовать атрибут ValueSource:

И источники параметров для теста, FirstValueSource и SecondValueSource, могут быть определены как:

И соответствующий вывод метода тестирования выглядит следующим образом:

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

Весь код, использованный в этой статье, можно найти в моем репозитории GitHub.

Надеюсь, что моя статья поможет другим.