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

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

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

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

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

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

Ответы [ 5 ]

6 голосов
/ 13 октября 2009

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

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

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

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

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

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

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

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

2 голосов
/ 13 октября 2009

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

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

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

1 голос
/ 13 октября 2009

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

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

1 голос
/ 13 октября 2009

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

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

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

0 голосов
/ 13 октября 2009

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

...