Используйте атрибуты теста NUnit для создания входных данных метода
Посмотрим правде в глаза, нет ничего хуже, чем пытаться понять код, который вы написали 3 месяца назад. Ну, если честно, пытаться понять тестовый код, который вы написали 3 месяца назад, еще хуже.
И худшее из худшего — это когда ваши коллеги пытаются понять тестовый код, который вы написали 3 месяца назад.
Мне действительно неловко, когда это происходит, особенно потому, что я уважаю их время — самое дорогое, что есть у любого из нас.
В этой статье я расскажу вам о 5 способах использования NUnit Test Framework, чтобы упростить ваш тестовый код и сделать его более читабельным. Я собираюсь сосредоточиться только на входных данных для ваших модульных тестов, а не на самом тесте или правильном способе назвать ваши тесты.
Простой тест для начала
Class1
реализует проверку TrueOnEvenNumbers
. Вы можете увидеть повторение с несколькими утверждениями, что совершенно не нужно. Хуже, когда что-то подобное делается в цикле внутри тестового метода.
Наличие одного утверждения для каждого теста облегчает понимание и поддержку тестового кода. Для этого воспользуемся атрибутом NUnit TestCase
.
1. Атрибут TestCase
NUnit будет запускать тест один раз для атрибута TestCase
. Рефакторинговый тестовый метод теперь принимает входные данные и возвращает выходные данные. Входные данные берутся из первого параметра атрибута TestCase
. Вывод проверяется на соответствие свойству ExpectedResult
атрибута TestCase
. Мне это нравится, так как тест теперь больше фокусируется на проверяемой логике и имеет одно утверждение.
Вывод теста NUnit:
Вывод показывает точное значение параметра, которое передается при каждом вызове метода тестирования.
Логика метода тестирования, используемая здесь, следующая:
- Четные числа возвращают true
- Числа, которые не являются четными числами, возвращают 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.
Надеюсь, что моя статья поможет другим.