Контракты кода модульного тестирования - PullRequest
6 голосов
/ 02 марта 2011

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

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

if (hours < 0 || hours > 8)
    throw new ArgumentOutOfRangeException("hours", "Hours must be between 0 and 8");

Я просто заменил это на

Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8");

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

    public static DurationUnit HoursAsDuration(int hours)
    {
        Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8");

        switch (hours)
        {
            case 1:
            case 2:
                return DurationUnit.Quarter;
            case 3:
            case 4:
                return DurationUnit.Half;
            case 5:
            case 6:
                return DurationUnit.ThreeQuarter;
            case 7:
            case 8:
                return DurationUnit.Full;
            default:
                return DurationUnit.None;
        }
    }

    [Test]
    public void CanConvertToDuration()
    {
        Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(0));
        Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(1));
        Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(2));
        Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(3));
        Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(4));
        Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(5));
        Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(6));
        Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(7));
        Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(8));

        //Would expect this to cause an issue
        Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(9));
    }

Тест возвращает значение true, но я бы ожидал, что контракт кода остановит значение «9», входящее в оператор switch.Это ожидаемое поведение?

Ответы [ 3 ]

1 голос
/ 02 марта 2011

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

Я бы ожидал, что есть способ выразить это в Code Contracts, но я не знаком с этим языком контракта, толькос другим.Философия остается той же: если вы хотите, чтобы чек был частью производственной сборки, то условие чека не является предварительным условием.С другой стороны, договор может (должен) выражать, что проверка выполнена и что каждый случай обрабатывается надлежащим образом.

0 голосов
/ 02 марта 2011

Хорошо, теперь у меня есть код, выдающий ожидаемую ошибку, включив опцию «Выполнить проверку контракта во время выполнения» в свойствах проекта в Visual Studio.

Означает ли это, что при выпуске в производство эти кодовые контракты фактически игнорируются?

Я, безусловно, неправильно понимаю, как должны использоваться контракты кода, поэтому, если кто-то может указать мне направление к статье о передовой практике, я был бы признателен.

Страница MSDN гласит:

"Большинство методов в классе контракта скомпилированы условно; то есть компилятор вызывает эти методы только тогда, когда вы определяете специальный символ, CONTRACTS FULL, используя директиву #define. CONTRACTS FULL позволяет вам писать контракты в вашем код без использования директив #ifdef; вы можете создавать различные сборки, некоторые с контрактами, а некоторые без. "

Значит ли это, что мне все равно было бы лучше использовать if ... then .. throw .. для чего-либо публичного? Проверки проверки параметров действительно помогают сократить повреждение данных, поскольку они отмечают точку сбоя как можно раньше.

0 голосов
/ 02 марта 2011

Я думаю, вам нужно поменять местами тесты по параметру часов.

Вы должны определить правило, которое будет проходить.

, поэтому я думаю, что это будет работать для вас ...

Contract.Requires<ArgumentOutOfRangeException>(hours < 0 && hours > 8, "Hours must be between 0 and 8");
...