Страницы

Поиск по вопросам

воскресенье, 30 сентября 2018 г.

Как правильно выбрать название для юнит-теста?

Это был обычный будний день, я начал писать очередной обычный тест, но при написании названия теста что-то пошло не так:
testCustomerRedirectUrlAfterSelectLastTransactionProcessShouldContainsUrlToConfirmRecurringProfilePageWhenTransactionTypeIsCreateRecurringProfile
Примерно на середине я начал осознавать что происходит что-то не то, но я не остановился и дописал название теста до конца. Коллеги не оценили такое длиннющее название теста, но мне оно нравится. Сейчас используется что-то вроде testCorrectChangeCustomerRedirectUrl, а детали того что тест тестирует скрыты внутри теста.
Я не могу понять это лвлап, либо я устал под вечер.
Вопрос: Каковы критерии выбора хорошего названия теста?
UPD: Пожалуйста, приведите названия тестов из ваших проектов.


Ответ

Название для тестов не надо выбирать красивое. Название нужно выбирать функциональное и по возможности короткое -- чтобы по минимальному количеству символов было понятно, что и под какими условиями он тестирует, а также чтобы можно было отличить конкретный тест от тысяч других.
Распространенные шаблоны наименования такие:
TestClass_TestMethod_ConditionAndExpectedResult (для юнит-тестов) TestMethod_Condition_ExpectedResult (для юнит-тестов) ConditionAndExpectedResult (для интеграционных тестов, которые тестируют целые блоки функциональности через некоторую входную точку)
При этом если у вас в частях Condition/ExpectedResult слишком много разных условий/результатов, объединенных по "И", то вам нужно пересмотреть либо главную цель теста (что он тестирует), либо главное условие, которое отличает тест от других, и разбить его на несколько отдельных тестов.

Я ратую прежде всего за то, что название должно быть информативным, но при этом настолько коротким, насколько возможно. Тут точно так же как и со всем остальным кодом -- чем меньше кода, тем меньше времени нужно чтобы его понять, тем проще разбираться с ним. Судя по вашему названию, это не простой маленький юнит-тест, а что-то побольше, поэтому совсем коротким названием тут не обойтись. В вашем случае, если тест класс у вам уже для Customer, я бы ограничился названием SelectLastTransactionProcess_CreateRecurringProfile_RedirectUrlShouldContainConfirmation. В вашем названии много повторений слов: transaction, url, recurring profile и т.д. Они избыточны.
Между длиной и информативностью названия безусловно должен быть баланс. Достаточно, чтоб названия были понятны разработчикам внутри проекта, которые уже обладают контекстом и способны понять, о чем этот тест. И если для этого нужно длину названия сделать не 30 символов, а 40, сделайте. Но не нужно стремиться к тому, чтоб названия были понятны каждому встречному, попутно рассказывая обо всей системе, поскольку это приводит к таким вот километровым названиям, в которых сложно разобраться. Посмотрите на свой обычный код, посмотрите на названия методов. Вы ведь не описываете в названии метода каждую его деталь, каждую строчку? Вы описываете нечто главное, а остальное спрятано внутри. Точно так же и с тестовыми методами.

Кто-нибудь может ещё рассказать что делать с названиями интеграционных тестов, > где 100500 различных условий? К примеру биллинг, принимает на вход 5-10 видов прайс-листов и в зависимости от их комбинаций и комбинаций их параметров (тоже примерно 5-10) должен выдавать различные суммы на выход. Контейнер отправляемый в биллинг занимает ~30 строчек. Если в стиле поста называть тесты то это будет testPayoutDebtorToGateOntopGateTransactionAmountGateToCreditorFlatPayinDebtorTo‌​GateOntopTotalTransactionAmountGateToCreditorOntopTransactionAmount, причем не с полным контекстом. Нужно рассчитать итоговую сумму исходя из того что прайс-листы могли быть настроены следующим образом: Тип комиссии прайс-листа типа основной сделки - inside/total, комиссия 0.1% + 0.5руб cверху, расчет вести от оборота. Второй комиссионный прайс-лист ontop/gate.. ещё в таком же стиле раз 10 и пара неявных зависимостей прайс-листов друг от друга.
Я бы сказал, что вам нужен параметрический тест. Это такой тест, который одним кодом тестирует разные наборы данных. Например, в терминах тестового фреймворка xUnit параметрический тест метода Calculator.Add() может выглядеть так:
[Theory] // это параметрический тест [InlineDate(1, 2, 3)] // наборы данных, т.е. параметры теста [InlineDate(0, 1, 1)] [InlineDate(-1, 1, 0)] public void Calculator_Add_ShouldReturnCorrectResult(int a, int b, int expectedResult) { var result = Calculator.Add(a, b); Assert.AreEqual(result, expectedResult); }
С параметрическими тестами вам не нужно перечислять все условия в названиях -- название содержит только суть теста, что именно тестируется, конкретный кейс. В вашем случае это что-то вроде РасчетИтоговойСтоимости_ПоОсновнойИДополнительнойСделке (на английский сами переведете, вам область понятнее). А выглядеть ваш тестовый метод может так (при этом в xUnit тестовые данные можно подставлять из свойства и даже из отдельного объекта):
[Theory] [PropertyData("PriceData")] // тестовые данные находятся в отдельном свойстве public void РасчетИтоговойСтоимости_ПоОсновнойИДополнительнойСделке( ComissionType mainComissionType, Comission mainComission, CalculationType mainCalculationType, ComissionType auxComissionType, Comission auxComission, CalculationType auxCalculationType, double expectedPrice) { // код теста }
public static IEnumerable PriceData { get { // данные можете захардкодить, а можете прочитать из файла return new[] { new object[] { // основная сделка ComissionType.InsideTotal, new Comission(0.1, 0.5), CalculationType.ОтОборота, // дополнительная сделка ComissionType.OnTopGate, new Comission(0.42, 0.99), CalculationType.ОтБалды, // результат 100500 }, // и так далее для других пар }; } }
Я думаю во многих тестовых фреймворка есть возможность создания параметрических тестов. Способ задания параметров может отличаться, но суть останется та же: данные выносятся в секцию с данным, в названии теста остается только название кейса.
Дополнительную информацию о параметрических тестах можной найти в блоге Сергея Теплякова.

Комментариев нет:

Отправить комментарий