47 votes

Comment se fait que vous ne pouvez pas attraper Contrat de Code exceptions?

Système.Diagnostics.Des contrats.ContractException n'est pas accessiable dans mon projet de test. Remarque: ce code est purement moi-même de déconner avec mes shiney nouvelle copie de Visual Studio, mais j'aimerais savoir ce que je fais mal.

Je suis l'aide de l'édition professionnelle de VS, donc je n'ai pas de vérification statique. Afin de toujours utiliser des contrats de code (que j'aime) j'ai pensé que la seule façon de ma méthode de travail est d'attraper l'exception est levée lors de l'exécution, mais je ne suis pas à trouver ce possible.

TestMethod

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

Méthode

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

Erreur

Erreur 1 'Système.Diagnostics.Des contrats.ContractException' est inaccessible
en raison de son niveau de protection.

Modifier

Après un peu plus de la pensée que j'en suis venu à la conclusion discuté dans les commentaires, ainsi que les suivants. Étant donné une méthode, si cela avait une exigence qui peut être exprimé dans le Code du formulaire de Contrat, je ferais des tests en tant que tel.

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

Cela permettrait de s'assurer que le contrat est une partie du code, il ne sera pas supprimé. Ceci nécessiterait un Contrat de Code pour réellement lancer l'exception spécifiée, cependant. Dans certains cas, cela ne serait pas nécessaire cependant.

70voto

Jon Skeet Points 692016

C'est délibéré - bien qu'une légère douleur pour les tests.

Le point est que dans le code de production ne doit jamais vous voulez prendre un contrat d'exception; il indique un bug dans votre code, vous ne devriez pas attendre plus que arbitraire exceptions inattendues qui peuvent vous voulez prendre à droite en haut de votre pile d'appel de sorte que vous pouvez passer à la prochaine demande. Fondamentalement, vous ne devriez pas voir contrat d'exceptions qui peuvent être "gérée" en tant que tels.

Maintenant, pour les tests c'est une douleur... mais avez-vous vraiment envie de tester vos contrats de toute façon? N'est-ce pas un peu comme les tests que le compilateur ne vous empêche de passer dans un string pour une méthode qui a un int paramètre? Vous avez déclaré le contrat, il peut être documentés de façon appropriée, et appliquées de manière appropriée (en fonction de paramètres, de toute façon).

Si vous ne voulez tester contrat exceptions, vous pouvez prendre un nu - Exception dans le test et la vérification de son nom complet, ou vous pouvez s'amuser avec les Contract.ContractFailed événement. J'attendrais les tests unitaires des cadres pour la prise en charge intégrée pour cela, au fil du temps - mais ça va prendre un peu de temps pour y arriver. En attendant, vous souhaitez probablement une méthode utilitaire de s'attendre à une violation de contrat. Une implémentation possible:

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.
    }
}

8voto

Stephen Drew Points 524

EDIT: j'ai eu une conversion et de ne plus utiliser ExpectedException ou cet attribut ci-dessous, mais plutôt codé des méthodes d'extension:

AssertEx.Throws<T>(Action action);
AssertEx.ThrowsExact<T>(Action action);
AssertEx.ContractFailure(Action action);

Ces permettez-moi d'être plus précis sur l'endroit où l'exception est levée.

Exemple de ContractFailure méthode:

    [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Cannot catch ContractException")]
    public static void ContractFailure(Action operation)
    {
        try
        {
            operation();
        }
        catch (Exception ex)
        {
            if (ex.GetType().FullName == "System.Diagnostics.Contracts.__ContractsRuntime+ContractException")
                return;

            throw;
        }

        Assert.Fail("Operation did not result in a code contract failure");
    }

J'ai créé un attribut pour MSTest, qui se comporte de façon similaire à la ExpectedExceptionAttribute:

public sealed class ExpectContractFailureAttribute : ExpectedExceptionBaseAttribute
{
    const string ContractExceptionName = "System.Diagnostics.Contracts.__ContractsRuntime+ContractException";

    protected override void Verify(Exception exception)
    {
        if (exception.GetType().FullName != ContractExceptionName)
        {
            base.RethrowIfAssertException(exception);
            throw new Exception(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Test method {0}.{1} threw exception {2}, but contract exception was expected. Exception message: {3}",
                    base.TestContext.FullyQualifiedTestClassName,
                    base.TestContext.TestName,
                    exception.GetType().FullName,
                    exception.Message
                )
            );
        }
    }
}

Et cela peut être utilisé de la même façon:

    [TestMethod, ExpectContractFailure]
    public void Test_Constructor2_NullArg()
    {
        IEnumerable arg = null;

        MyClass mc = new MyClass(arg);
    }

2voto

user341451 Points 11

dans le vs2010 rtm, le nom complet a été changé pour "le Système de.Diagnostics.Des contrats.__ContractsRuntime+ContractException". HTH

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X