У меня есть модульный тест, который выглядит так:
[Test]
public void Should_create_person()
{
Assert.DoesNotThrow(() => new Person(Guid.NewGuid(), new DateTime(1972, 01, 01));
}
Я утверждаю, что здесь создается объект Person, т. Е. Проверка не завершается неудачей. Например, если Guid имеет значение null или дата рождения ранее, чем 01.01.1900, то проверка не будет выполнена, и будет выдано исключение (что означает, что тест не пройден).
Конструктор выглядит так:
public Person(Id id, DateTime dateOfBirth) :
base(id)
{
if (dateOfBirth == null)
throw new ArgumentNullException("Date of Birth");
elseif (dateOfBith < new DateTime(1900,01,01)
throw new ArgumentException("Date of Birth");
DateOfBirth = dateOfBirth;
}
Это хорошая идея для теста?
Примечание . Я следую классическому подходу к модульному тестированию модели предметной области, если это имеет какое-либо отношение.
c#
unit-testing
constructors
w0051977
источник
источник
Should_create_person
? Что должен создать человек? Дайте ему значимое имя, какCreating_person_with_valid_data_succeeds
.Ответы:
Это действительный тест (хотя и довольно усердный), и я иногда делаю это для проверки логики конструктора, однако, как упоминал Лаив в комментариях, вы должны спросить себя, почему.
Если ваш конструктор выглядит так:
Много ли смысла в тестировании бросает? Правильно ли назначены параметры, я могу понять, но ваш тест довольно излишний.
Однако, если ваш тест делает что-то вроде этого:
Тогда ваш тест становится более актуальным (поскольку вы на самом деле генерируете исключения где-то в коде).
Одна вещь, я бы сказал, как правило, плохая практика - иметь много логики в конструкторе. Базовая проверка (например, проверки null / default, которые я делаю выше) в порядке. Но если вы подключаетесь к базам данных и загружаете чьи-то данные, тогда код начинает пахнуть ...
Из-за этого, если ваш конструктор стоит протестировать (потому что в нем много логики), возможно, что-то еще не так.
Вы почти наверняка будете иметь другие тесты, охватывающие этот класс на уровнях бизнес-логики, конструкторы и назначения переменных почти наверняка получат полное покрытие из этих тестов. Поэтому может быть бессмысленно добавлять специальные тесты специально для конструктора. Тем не менее, ничто не является черно-белым, и я бы ничего не имел против этих тестов, если бы я проверял их код - но я бы задал вопрос, добавляют ли они большую ценность сверх тестов где-либо еще в вашем решении.
В вашем примере:
Вы не только делаете проверку, но и вызываете базовый конструктор. Для меня это дает больше оснований для проведения этих тестов, так как они имеют логику конструктора / проверки, теперь разделенную на два класса, что уменьшает видимость и увеличивает риск неожиданных изменений.
TLDR
Эти тесты имеют определенную ценность, однако логика проверки / назначения, вероятно, будет охватываться другими тестами в вашем решении. Если в этих конструкторах много логики, которая требует значительного тестирования, то это наводит меня на мысль о неприятном запахе кода.
источник
PersonBirthdate
), который выполняет проверку даты рождения. Аналогичным образомGuid
проверка может быть реализована вId
классе. Это означает, что вам действительно больше не нужно иметь эту логику проверки вPerson
конструкторе, поскольку невозможно создать логику с недопустимыми данными - за исключениемnull
ссылок. Конечно, вы должны написать тесты для двух других классов :)Здесь уже хороший ответ, но я думаю, что стоит упомянуть еще одну вещь.
При выполнении TDD «по книге» необходимо сначала написать тест, который вызывает конструктор, даже до того, как конструктор будет реализован. Этот тест на самом деле может выглядеть как тот, который вы представили, даже если бы внутри реализации конструктора была нулевая логика проверки.
Также обратите внимание, что для TDD нужно сначала написать еще один тест, например
перед добавлением проверки для
DateTime(1900,01,01)
конструктора.В контексте TDD показанный тест имеет смысл.
источник