Итак, у меня есть модуль аутентификации, который я написал некоторое время назад. Теперь я вижу ошибки моего пути и пишу для него юнит-тесты. При написании юнит-тестов мне трудно придумывать хорошие имена и хорошие области для тестирования. Например, у меня есть такие вещи, как
- RequiresLogin_should_redirect_when_not_logged_in
- RequiresLogin_should_pass_through_when_logged_in
- Login_should_work_when_given_proper_credentials
Лично я думаю, что это немного некрасиво, хотя это кажется "правильным". У меня также возникают проблемы с дифференциацией тестов, просто просматривая их (мне нужно прочитать имя метода, по крайней мере, дважды, чтобы узнать, что только что провалилось)
Итак, я подумал, что, возможно, вместо того, чтобы писать тесты, которые просто тестируют функциональность, возможно, написать набор тестов, которые охватывают сценарии.
Например, это тестовая заглушка, которую я придумал:
public class Authentication_Bill
{
public void Bill_has_no_account()
{ //assert username "bill" not in UserStore
}
public void Bill_attempts_to_post_comment_but_is_redirected_to_login()
{ //Calls RequiredLogin and should redirect to login page
}
public void Bill_creates_account()
{ //pretend the login page doubled as registration and he made an account. Add the account here
}
public void Bill_logs_in_with_new_account()
{ //Login("bill", "password"). Assert not redirected to login page
}
public void Bill_can_now_post_comment()
{ //Calls RequiredLogin, but should not kill request or redirect to login page
}
}
Это слышал о шаблоне? Я видел истории о приеме и тому подобное, но это принципиально иное. Большая разница в том, что я придумываю сценарии, чтобы «вывести» тесты из строя. Вместо того, чтобы вручную пытаться придумать возможные взаимодействия, которые мне нужно будет проверить. Кроме того, я знаю, что это поощряет модульные тесты, которые не проверяют только один метод и класс. Я думаю, что это нормально, хотя. Кроме того, я знаю, что это вызовет проблемы, по крайней мере, для некоторых платформ тестирования, поскольку они обычно предполагают, что тесты независимы друг от друга и порядок не имеет значения (где это будет в этом случае).
Во всяком случае, это рекомендуемый шаблон вообще? Или это было бы идеально подходит для интеграционных тестов моего API, а не в качестве «модульных» тестов? Это всего лишь личный проект, поэтому я открыт для экспериментов, которые могут или не могут пойти хорошо.
_test
добавлением, и использую комментарии, чтобы отметить, каких результатов я ожидаю. Если это личный проект, найдите какой-то стиль, который вам удобнее, и придерживайтесь его.Ответы:
Да, это хорошая идея, чтобы дать вашим тестам названия примеров сценариев, которые вы тестируете. И использование вашего инструмента модульного тестирования для более чем просто модульных тестов, возможно, тоже хорошо, многие люди делают это с успехом (и я тоже).
Но нет, определенно не стоит писать ваши тесты таким образом, чтобы порядок выполнения тестов имел значение. Например, NUnit позволяет пользователю интерактивно выбирать, какой тест он хочет выполнить, так что это больше не будет работать так, как задумано.
Этого можно легко избежать, отделяя основную часть тестирования каждого теста (включая «утверждение») от частей, которые устанавливают вашу систему в правильное начальное состояние. Используя приведенный выше пример: напишите методы создания учетной записи, входа в систему и оставьте комментарий - без каких-либо утверждений. Затем используйте эти методы в разных тестах. Вам также необходимо добавить некоторый код в
[Setup]
метод ваших тестовых приборов, чтобы убедиться, что система находится в правильно определенном начальном состоянии (например, пока нет учетных записей в базе данных, нет подключенных пользователей и т. Д.).РЕДАКТИРОВАТЬ: Конечно, это, кажется, противоречит "истории" характера ваших тестов, но если вы дадите своим вспомогательным методам осмысленные имена, вы найдете свои истории в каждом тесте.
Итак, это должно выглядеть так:
источник
Проблема с рассказом истории с помощью модульных тестов заключается в том, что в ней не указано, что модульные тесты должны организовываться и выполняться полностью независимо друг от друга.
Хороший модульный тест должен быть полностью изолирован от всего другого зависимого кода, это самая маленькая единица кода, которую можно протестировать.
Это дает преимущество в том, что, наряду с подтверждением работоспособности кода, в случае неудачного прохождения теста вы получаете диагноз того, где именно код является бесплатным, бесплатно. Если тест не изолирован, вы должны посмотреть, от чего зависит, чтобы точно выяснить, что пошло не так, и упустить главное преимущество модульного тестирования. Наличие порядка выполнения также может вызвать много ложных отрицаний, если тест не пройден, возможно, что следующие тесты не пройдут, несмотря на то, что код, который они тестируют, работает отлично.
Хорошая статья более подробно - классика по грязным гибридным тестам .
Чтобы сделать классы, методы и результаты удобочитаемыми, большое тестирование Art of Unit использует соглашение об именах
Тестовый класс:
Методы испытаний:
Чтобы скопировать пример @Doc Brown, вместо использования [Setup], который выполняется перед каждым тестом, я пишу вспомогательные методы для создания изолированных объектов для тестирования.
Таким образом, у провальных тестов есть осмысленное имя, которое дает вам некоторое описание того, какой именно метод провалился, условия и ожидаемый результат.
Именно так я всегда писал модульные тесты, но у друга был большой успех с Геркиным .
источник
То, что вы описываете, для меня больше похоже на Behavior Driven Design (BDD), чем на модульное тестирование. Взгляните на SpecFlow, который является технологией .NET BDD, основанной на DSL Gherkin .
Мощный материал, который любой человек может читать / писать, не зная ничего о кодировании. Наша команда тестировщиков пользуется большим успехом, используя ее для наших интеграционных тестов.
Что касается соглашений для модульных тестов, ответ @ DocBrown кажется убедительным.
источник
assert(value === expected)
BDD =value.should.equals(expected)
+ вы описываете функции в слоях, которые решают проблему «независимости модульного теста». Это отличный стиль!