Сколько модульных тестов я должен написать для функции / метода? - PullRequest
22 голосов
/ 21 сентября 2008

Вы пишете один тест на функцию / метод, с несколькими проверками в тесте, или тест для каждой проверки?

Ответы [ 12 ]

30 голосов
/ 21 сентября 2008

Один тест на проверку и суперописательные имена, на экземпляр:

@Test
public void userCannotVoteDownWhenScoreIsLessThanOneHundred() {
 ...
}

Как только одно утверждение, так и использование хороших имен дает мне лучший отчет, когда тест не пройден. Они кричат ​​мне: «Ты нарушил ЭТО правило!».

5 голосов
/ 21 сентября 2008

У меня есть тест на возможность , которую предлагает функция. Однако каждый тест может иметь несколько утверждений. Название тестового примера указывает на тестируемую возможность.

Обычно для одной функции у меня есть несколько тестов "солнечный день" и один или несколько сценариев "дождливый день", в зависимости от их сложности.

4 голосов
/ 21 сентября 2008

BDD (разработка, управляемая поведением)

Хотя я все еще учусь, в основном TDD организовано / сфокусировано на том, как на самом деле будет использоваться ваше программное обеспечение ... НЕ на том, как оно будет разрабатываться / создаваться.

Wikipedia Общая информация

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

3 голосов
/ 21 сентября 2008

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

Итак, в Python я считаю, что такой тест правильный :

def testGetCountReturnsCountAndEnd(self):
    count, endReached = self.handler.getCount()
    self.assertEqual(count, 0)
    self.assertTrue(endReached)

но этот должен быть разделен на два метода тестирования:

def testGetCountReturnsOneAfterPut(self):
    self.assertEqual(self.handler.getCount(), 0)
    self.handler.put('foo')
    self.assertEqual(self.handler.getCount(), 1)

Конечно, в случае длинных и часто используемых групп утверждений мне нравится создавать собственные методы утверждений - они особенно полезны для сравнения сложных объектов.

2 голосов
/ 21 сентября 2008

Я пишу, по крайней мере, один тест для каждого метода, а иногда и больше, если метод требует некоторой другой настройки для проверки хороших и плохих случаев.

Но вы должны НИКОГДА не проверять более одного метода в одном модульном тесте. Это уменьшает объем работы и ошибки в исправлении вашего теста в случае изменения вашего API.

2 голосов
/ 21 сентября 2008

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

1 голос
/ 21 сентября 2008

Мне нравится иметь тест на проверку в методе и иметь полное имя для метода теста Например:

testAddUser_shouldThrowIllegalArgumentExceptionWhenUserIsNull

1 голос
/ 21 сентября 2008

В Java / Eclipse / JUnit я использую две исходные директории (src и test) с одним и тем же деревом. Если у меня есть src / com / mycompany / what / TestMePlease с методами, достойными тестирования (например, deleteAll (List <?> Stuff), генерирует MyException ), я создаю test / com / mycompany / что угодно / TestMePleaseTest с методами для тестирования различных вариантов использования / сценариев:

@Test
public void deleteAllWithNullInput() { ... }

@Test(expect="MyException.class") // not sure about actual syntax here :-P
public void deleteAllWithEmptyInput() { ... }

@Test
public void deleteAllWithSingleLineInput() { ... }

@Test
public void deleteAllWithMultipleLinesInput() { ... }

Мне проще иметь разные чеки.

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

@Test
public void insertAndDelete() { 
    assertTrue(/*stuff does not exist yet*/);
    createStuff();
    assertTrue(/*stuff does exist now*/);
    deleteStuff();
    assertTrue(/*stuff does not exist anymore*/);
}

Не знаю, есть ли более разумные способы сделать это, чтобы сказать вам правду ...

1 голос
/ 21 сентября 2008

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

1 голос
/ 21 сентября 2008

Я бы предложил тестовый пример для каждой проверки. Чем больше вы держите атом, тем лучше ваши результаты!

Хранение нескольких проверок в одном тесте поможет вам создать отчет о том, сколько функций необходимо исправить.

Ведение атомного теста покажет вам общее качество!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...