Каким образом Вы не можете поймать исключения Контракта Кода?

Система. Диагностика. Контракты. ContractException не доступен в моем тестовом проекте. Обратите внимание, что этот код просто самостоятельно бездельничает с моей солнечной новой копией Visual Studio, но я хотел бы знать то, что я делаю неправильно.

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

TestMethod

[TestMethod, ExpectedException(typeof(System.Diagnostics.Contracts.ContractException))]
public void returning_a_value_less_than_one_throws_exception()
{
    var person = new Person();
    person.Number();
}

Метод

public int Number()
{
    Contract.Ensures(Contract.Result<int>() >= 0);
    return -1;
}

Ошибка

Error 1 'System.Diagnostics.Contracts.ContractException' is inaccessible
due to its protection level.

Править

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

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void value_input_must_be_greater_than_zero()
{
    // Arrange
    var person = new Person();
    // Act
    person.Number(-1);
}

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

47
задан Luke Girvin 2 June 2015 в 09:47
поделиться

2 ответа

Это преднамеренно, хотя и небольшая боль для тестирования.

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

Теперь, для тестирования это боль... но вы действительно хотите проверить свои контракты в любом случае? Разве это не похоже на тестирование того, что компилятор останавливает вас от передачи строки string методу, который имеет параметр int? Вы объявили контракт, он может быть задокументироват соответствующим образом и применен соответствующим образом (во всяком случае, на основе настроек).

Если вы do хотите протестировать исключения из контракта, вы можете либо поймать голое Exception в тесте и проверить его полное имя, либо вы можете повозиться с событием Contract.ContractFailed .. Я ожидаю, что фреймворки модульного тестирования будут иметь встроенную поддержку для этого с течением времени, но это займет некоторое время, чтобы добраться туда. В то же время вы, вероятно, хотите иметь служебный метод, чтобы ожидать нарушения контракта. Одна из возможных реализаций:

const string ContractExceptionName =
    "System.Diagnostics.Contracts.__ContractsRuntime.ContractException";

public static void ExpectContractFailure(Action action)
{
    try
    {
        action();
        Assert.Fail("Expected contract failure");
    }
    catch (Exception e)
    {
        if (e.GetType().FullName != ContractExceptionName)
        {
            throw;
        }
        // Correct exception was thrown. Fine.
    }
}
69
ответ дан 26 November 2019 в 19:43
поделиться

в vs2010 rtm полное название было изменено на "System.Diagnostics.Contracts.__ContractsRuntime+ContractException". HTH

2
ответ дан 26 November 2019 в 19:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: