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

Контракты с кодом .NET 4.0 - Как они повлияют на модульное тестирование?

Например, эта статья знакомит их.

В чем преимущество?

Статический анализ кажется прохладным, но в то же время он предотвратит возможность передачи null в качестве параметра в unit test. (если вы следовали примеру в статье)

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

Обновление

Играя с кодовыми контрактами, я немного разочарован. Например, на основе кода в принятом ответе:

public double CalculateTotal(Order order)
{
    Contract.Requires(order != null);
    Contract.Ensures(Contract.Result<double>() >= 0);
    return 2.0;
}

Для модульного тестирования вы еще должны писать тесты, чтобы гарантировать, что null не может быть передан, а результат больше или равен нулю, если контракты являются бизнес-логикой. Другими словами, если бы я должен был удалить первый контракт, тесты не сломались бы, если бы у меня не было теста для этой функции. Это основано не на использовании статического анализа, встроенного в лучшие (конечные и т.д.) Выпуски Visual Studio.

По сути, все они сводятся к альтернативному написанию традиционных операторов if. Мой опыт, фактически использующий TDD, с кодовыми контрактами показывает, почему и как я об этом говорил.

4b9b3361

Ответ 1

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


public class Order
{
    public IEnumerable Items { get; }
}

public class OrderCalculator
{
    public double CalculateTotal(Order order)
    {
        Contract.Requires(order != null);
        Contract.Ensures(Contract.Result<double>() >= 0);

        return 2.0;
    }
}

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

Ответ 2

В чем преимущество?

Скажем, что вы хотите убедиться, что метод никогда не возвращает null. Теперь с модульными тестами вам нужно написать кучу тестовых примеров, в которых вы вызываете метод с различными входами и убедитесь, что вывод не равен нулю. Проблема в том, что вы не можете протестировать все возможные входы.

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

Меньшая работа, гарантия совершенства. Что не нравится?

Ответ 3

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

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

Вы можете указать, что значение null является допустимым в контракте.

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

Ответ 4

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

Если я думаю об этом с этой точки зрения, я предполагаю, что он может/может изменить процедуру из стандартной

  • создать метод (только подпись)
  • создать Unit test → выполнить тест
  • запустите тест: пусть он не работает
  • реализовать метод, взломать его до конца, чтобы заставить его работать.
  • запустите тест: см. прохождение
  • реорганизовать ваш (возможно, грязный) метод
  • (повторите тест, чтобы увидеть, что вы ничего не сломали)

Это будет очень сложная процедура модульного тестирования. В таком контексте, я думаю, вы могли бы вставлять кодовые контракты между 1-й и 2-й точками, например

  • создать метод (только подпись)
  • вставить кодовые контракты для входных параметров методов
  • создать Unit test → выполнить тест
  • ...

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

Изменить

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