Подтвердить что ты не робот

Должен ли я дублировать тесты для удобства перегрузки?

Мне очень часто приходится делать удобные перегрузки для методов. Вот пример того, что я могу сделать:

public void Encode(string value) {
    Encode(value, DefaultEncoding);
}

public void Encode(string value, Encoding encoding) { 
    // ... 
}

Я начинаю уделять больше внимания единичному тестированию, а методы тестирования, подобные этому, приводят к некоторым препятствиям, я не уверен, что я доверяю себе, чтобы идти в одиночку. Первая и самая важная проблема заключается в том, следует ли дублировать тесты для обеих перегрузок. Например, оба метода должны вызывать ArgumentNullException, если значение равно null; правильнее ли распознавать, что может быть другая логика и написать два теста, или лучше предположить, что удобные перегрузки не имеют собственной логики?

У меня также есть вторичная проблема. Моя схема именования такая же, как у Роя Ошерова: "MemberName_State_ExpectedResult". Если я повторяю тесты, у меня возникают конфликтующие имена, не вводя какое-либо соглашение об именовании нечетных имен. Как вы справляетесь с этим, если вы дублируете тесты?

4b9b3361

Ответ 1

"написать два теста или лучше предположить, что удобные перегрузки не имеют собственной логики?"

Umm.... Ваши тесты не определяются "предположениями". Они определяются дизайном класса, который вы тестируете.

Вы ничего не делаете на основе "предположений".

Если функция удобства на самом деле является удобной функцией, она должна делать то же самое, и вы должны написать тест, демонстрирующий, что оба варианта метода фактически делают одно и то же.

Если "может быть другая логика" (1), это не очень удобная функция, и (2) вы должны написать тест, который демонстрирует, что оба варианта метода действительно делают правильную вещь (что может быть одинаковым с разными логики или могут быть разными, я не могу сказать из вопроса.)

"MemberName_State_ExpectedResult. Если я дублирую тесты, у меня есть конфликтующие имена"

Избегайте глупых вопросов согласованности. Если у вас есть тот же метод с разными сигнатурами, то это соглашение об именах не очень хорошо, не так ли? Придерживаясь этого добросовестно, несмотря на проблемы, это глупая последовательность.

Вы не можете тривиально использовать это, когда у вас есть методы, которые отличаются только сигнатурами аргументов. Поэтому просто сделайте что-то, что работает для всех ваших функций удобства.

Ответ 2

То, что я обычно делаю, это сделать "реальный" метод виртуальным. Это означает, что я могу протестировать метод удобства, используя производный класс, специфичный для теста (обычно создаваемый динамическим макетом), чтобы проверить, правильно ли он вызывает "реальный" метод.

Если единственное различие между "реальным" методом и методом удобства - использование значения по умолчанию для определенного параметра, вы можете покрыть его одним unit test и двигаться дальше.

I второй ответ S.Lott относительно соглашения об именах.

Ответ 3

Я часто не тестирую методы удобства на тот же уровень детализации, что и основной метод, который они называют. Например, ваш аргумент ArgumentNullException. Я бы не тестировал его дважды. Я чувствую, что модульное тестирование - это тестирование белого ящика. Мне разрешено знать реализацию.

Конечно, это может означать, что я собираюсь сгореть, когда поеду и реорганизую позже, и добавлю функциональность к методу удобства. Но я довольно приличный, делая TDD (не полный фанатик, как вы можете сказать из первого абзаца). Поэтому я думаю, что я, скорее всего, напишу тест на эту новую функциональность и прикрою ее.

Я не утверждаю, что это более или менее правильно. Это то, что я делаю.

Ответ 4

Я думаю, что ответ проще, чем вы думаете: вас волнует, работают ли перегруженные методы или нет? Если вам небезразлично, что они работают, как вы знаете наверняка, если вы их не проверите?

Вам потребуется около 15 секунд, чтобы написать тест, который сравнивает вывод перегруженной функции с той, которую он перегружает. Сделайте это и двигайтесь дальше.

Ответ 5

Если все ваши конструкторы называют полностью определенный конструктор, я бы разбил тесты на
1) ваш текущий unit test, который должен быть чем-то вроде ConstructorShouldDoThisAndThat()
2) специализированные модульные тесты для перегрузок, с указанием того, по умолчанию используется перегрузка, например ConstructorWithNoEncodingShouldSetEncodingToDefaultEncoding()