Тестовые случаи, «когда», «что» и «почему»? - PullRequest
6 голосов
/ 04 октября 2008

Будучи новичком в разработке на основе тестирования, этот вопрос меня беспокоил. Сколько это слишком много? Что должно быть проверено, как это должно быть проверено, и почему это должно быть проверено? Примеры приведены в C # с NUnit, но я предполагаю, что сам вопрос не зависит от языка.

Вот два моих текущих примера тестов на объекте общего списка (при тестировании со строками функция инициализации добавляет три элемента {"Foo", "Bar", "Baz"}):

[Test]
public void CountChanging()
{
    Assert.That(_list.Count, Is.EqualTo(3));
    _list.Add("Qux");
    Assert.That(_list.Count, Is.EqualTo(4));
    _list[7] = "Quuuux";
    Assert.That(_list.Count, Is.EqualTo(8));
    _list.Remove("Quuuux");
    Assert.That(_list.Count, Is.EqualTo(7));
}

[Test]
public void ContainsItem()
{
    Assert.That(_list.Contains("Qux"), Is.EqualTo(false));
    _list.Add("Qux");
    Assert.That(_list.Contains("Qux"), Is.EqualTo(true));
    _list.Remove("Qux");
    Assert.That(_list.Contains("Qux"), Is.EqualTo(false));
}

Код довольно комментирует себя, поэтому я не буду вдаваться в подробности, но разве такого рода вещи зашли слишком далеко? Add() и Remove(), конечно, тестируются отдельно, так какой уровень я должен пройти с такого рода тестами? Должен ли я даже иметь такие тесты?

Ответы [ 4 ]

7 голосов
/ 04 октября 2008

Я бы сказал, что вы на самом деле тестируете классы эквивалентности. На мой взгляд, нет никакой разницы между добавлением в список из 3 или 7 элементов. Однако есть разница между 0, 1 и> 1 предметами. Первоначально у меня было бы 3 теста для каждого метода Add / Remove для этих случаев.

Как только ошибки начинают поступать от QA / пользователей, я бы добавил каждый такой отчет об ошибках в качестве контрольного примера; увидеть репродукцию ошибки, получив красную полосу; исправить ошибку, получив зеленую полосу. Каждый такой тест на «обнаружение ошибок» остается в силе - это моя сеть безопасности (читай: регрессионный тест), что даже если я снова сделаю эту ошибку, у меня будет мгновенный отзыв.

6 голосов
/ 04 октября 2008

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

Это действительно сложно определить объективно. Полагаю, я бы сказал, что слишком много ошибаюсь на стороне тестирования. Затем, когда тесты начинают вас раздражать, это особые тесты для рефакторинга / перепрофилирования (потому что они слишком хрупкие, или тестируют неправильные вещи, а их ошибки бесполезны).

2 голосов
/ 04 октября 2008

Несколько советов:

  1. Каждый тестовый сценарий должен проверять только одну вещь. Это означает, что структура тестового набора должна быть «setup», «execute», «assert». В ваших примерах вы смешиваете эти фазы. Попробуйте разделить ваши тестовые методы. Это упрощает просмотр именно того, что вы тестируете.

  2. Попробуйте дать вашим методам испытаний имя, которое описывает, что именно они тестируют. То есть три тестовых случая, содержащихся в вашем ContainsItem (), становятся следующими: containsReportsFalseIfTheItemHasNotBeenAdded (), containsReportsTrueIfTheItemHasBeenAdded (), содержитReportsFalseIfTheItemHasBeenAddedThenRemoved (). Я обнаружил, что принуждение к тому, чтобы придумать такое описательное имя, помогает мне осмыслить то, что я должен тестировать, прежде чем кодировать реальный тест.

  3. Если вы выполняете TDD, вы должны написать свои первые тесты и добавлять код в свою реализацию только в случае неудачного теста. Даже если вы на самом деле этого не сделаете, это даст вам представление о том, сколько тестов достаточно. В качестве альтернативы используйте инструмент покрытия. Для простого класса, такого как контейнер, вы должны стремиться к 100% охвату.

1 голос
/ 04 октября 2008

Является ли _list экземпляром класса, который вы написали? Если это так, я бы сказал, что тестирование это разумно. Хотя в таком случае, почему вы создаете собственный класс List?

Если это не код, который вы написали, не проверяйте его, если не подозреваете, что он каким-то образом глючит.


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

...