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

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

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

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

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

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

12.10.2009 21:34:42
5 ОТВЕТОВ

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

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

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

1
12.10.2009 21:45:56

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

0
12.10.2009 21:46:37

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

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

Вы ничего не делаете, основываясь на «предположениях».

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

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

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

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

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

6
13.10.2009 11:50:13
+1 на оба аккаунта. Простой способ проверить поведение удобного метода см. В моем ответе на этот вопрос.
Mark Seemann 13.10.2009 11:21:46

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

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

1
13.10.2009 10:43:51

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

Если единственное различие между «реальным» методом и вспомогательным методом заключается в использовании значения по умолчанию для определенного параметра, вы можете покрыть это с помощью одного модульного теста и двигаться дальше.

Я второй ответ С. Лотта относительно соглашения об именах.

2
13.10.2009 11:20:36