web-dev-qa-db-fra.com

Comment appliquer le message d'exception avec l'attribut ExpectedException

Je pensais que ces deux tests devraient se comporter de manière identique, en fait j'ai écrit le test dans mon projet en utilisant MS Test uniquement pour découvrir maintenant qu'il ne respecte pas le message attendu de la même manière que NUnit.

NUnit (échoue):

[Test, ExpectedException(typeof(System.FormatException), ExpectedMessage = "blah")]
public void Validate()
{
    int.Parse("dfd");
}

Test MS (réussite):

[TestMethod, ExpectedException(typeof(System.FormatException), "blah")]
public void Validate()
{
    int.Parse("dfd");
}

Quel que soit le message que je donne, le test ms passera.

Existe-t-il un moyen de faire échouer le test ms si le message n'est pas correct? Puis-je même créer mon propre attribut d'exception? Je préfère ne pas avoir à écrire un bloc try catch pour chaque test où cela se produit.

31
CRice

Ce deuxième paramètre mstest est un message qui est imprimé lorsque le test échoue. Le mstest réussira si une exception formate est levée. J'ai trouvé ce post qui peut être utile

http://blogs.msdn.com/b/csell/archive/2006/01/13/expectedexception-might-not-be-what-you-ve-expected.aspx

22
rcravens

Nous utilisons cet attribut partout et nous avons clairement mal compris le deuxième paramètre (honte à nous).

Cependant, nous l'avons certainement utilisé pour vérifier le message d'exception. Ce qui suit est ce que nous avons utilisé avec les conseils de cette page. Il ne gère pas la mondialisation ou les types d'exception hérités, mais il fait ce dont nous avons besoin. Encore une fois, l'objectif était simplement de RR "ExpectedException" et de l'échanger avec cette classe. (Bummer ExpectedException est scellé.)

public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
    public Type ExceptionType { get; set; }

    public string ExpectedMessage { get; set; }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType)
    {
        this.ExceptionType = exceptionType;
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
    {
        this.ExceptionType = exceptionType;

        this.ExpectedMessage = expectedMessage;
    }

    protected override void Verify(Exception e)
    {
        if (e.GetType() != this.ExceptionType)
        {
            Assert.Fail(String.Format(
                            "ExpectedExceptionWithMessageAttribute failed. Expected exception type: {0}. Actual exception type: {1}. Exception message: {2}",
                            this.ExceptionType.FullName,
                            e.GetType().FullName,
                            e.Message
                            )
                        );
        }

        var actualMessage = e.Message.Trim();

        if (this.ExpectedMessage != null)
        {
            Assert.AreEqual(this.ExpectedMessage, actualMessage);
        }

        Console.Write("ExpectedExceptionWithMessageAttribute:" + e.Message);
    }
}
28
BlackjacketMack

@rcravens est correct - le deuxième paramètre est un message qui est imprimé si le test échoue. Ce que j'ai fait pour contourner ce problème, c'est concevoir mes tests un peu différemment. Certes, je n'aime pas cette approche, mais ça marche.

[TestMethod]
public void Validate()
{
    try
    {
        int.Parse("dfd");

        // Test fails if it makes it this far
        Assert.Fail("Expected exception was not thrown.");
    }
    catch (Exception ex)
    {
        Assert.AreEqual("blah", ex.Message);
    }
}
12
Jeremy Wiggins

J'ai étendu la réponse de BlackjacketMack pour notre projet en ajoutant la prise en charge des combinaisons contient, insensible à la casse et ResourcesType-ResourceName.

Exemple d'utilisation:

public class Foo
{
    public void Bar(string mode)
    {
        if (string.IsNullOrEmpty(mode)) throw new InvalidOperationException(Resources.InvalidModeSpecified);
    }

    public void Bar(int port)
    {
        if (port < 0 || port > Int16.MaxValue) throw new ArgumentOutOfRangeException("port");
    }
}

[TestClass]
class ExampleClass
{
    [TestMethod]
    [ExpectedExceptionWithMessage(typeof(InvalidOperationException), typeof(Samples.Resources), "InvalidModeSpecified")]
    public void Raise_Exception_With_Message_Resource()
    {
        new Foo().Bar(null);
    }

    [TestMethod]
    [ExpectedExceptionWithMessage(typeof(ArgumentOutOfRangeException), "port", true)]
    public void Raise_Exeception_Containing_String()
    {
        new Foo().Bar(-123);
    }
}

Voici la classe mise à jour:

public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
    public Type ExceptionType { get; set; }

    public Type ResourcesType { get; set; }

    public string ResourceName { get; set; }

    public string ExpectedMessage { get; set; }

    public bool Containing { get; set; }

    public bool IgnoreCase { get; set; }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType)
        : this(exceptionType, null)
    {
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
        : this(exceptionType, expectedMessage, false)
    {
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage, bool containing)
    {
        this.ExceptionType = exceptionType;
        this.ExpectedMessage = expectedMessage;
        this.Containing = containing;
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName)
        : this(exceptionType, resourcesType, resourceName, false)
    {
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName, bool containing)
    {
        this.ExceptionType = exceptionType;
        this.ExpectedMessage = ExpectedMessage;
        this.ResourcesType = resourcesType;
        this.ResourceName = resourceName;
        this.Containing = containing;
    }

    protected override void Verify(Exception e)
    {
        if (e.GetType() != this.ExceptionType)
        {
            Assert.Fail(String.Format(
                            "ExpectedExceptionWithMessageAttribute failed. Expected exception type: <{0}>. Actual exception type: <{1}>. Exception message: <{2}>",
                            this.ExceptionType.FullName,
                            e.GetType().FullName,
                            e.Message
                            )
                        );
        }

        var actualMessage = e.Message.Trim();

        var expectedMessage = this.ExpectedMessage;

        if (expectedMessage == null)
        {
            if (this.ResourcesType != null && this.ResourceName != null)
            {
                PropertyInfo resourceProperty = this.ResourcesType.GetProperty(this.ResourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                if (resourceProperty != null)
                {
                    string resourceValue = null;

                    try
                    {
                        resourceValue = resourceProperty.GetMethod.Invoke(null, null) as string;
                    }
                    finally
                    {
                        if (resourceValue != null)
                        {
                            expectedMessage = resourceValue;
                        }
                        else
                        {
                            Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not get resource value. ResourceName: <{0}> ResourcesType<{1}>.",
                            this.ResourceName,
                            this.ResourcesType.FullName);
                        }
                    }
                }
                else
                {
                    Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not find static resource property on resources type. ResourceName: <{0}> ResourcesType<{1}>.",
                        this.ResourceName,
                        this.ResourcesType.FullName);
                }
            }
            else
            {
                Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Both ResourcesType and ResourceName must be specified.");
            }
        }

        if (expectedMessage != null)
        {
            StringComparison stringComparison = this.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
            if (this.Containing)
            {
                if (actualMessage == null || actualMessage.IndexOf(expectedMessage, stringComparison) == -1)
                {
                    Assert.Fail(String.Format(
                                    "ExpectedExceptionWithMessageAttribute failed. Expected message: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
                                    expectedMessage,
                                    e.Message,
                                    e.GetType().FullName
                                    )
                                );
                }
            }
            else
            {
                if (!string.Equals(expectedMessage, actualMessage, stringComparison))
                {
                    Assert.Fail(String.Format(
                                    "ExpectedExceptionWithMessageAttribute failed. Expected message to contain: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
                                    expectedMessage,
                                    e.Message,
                                    e.GetType().FullName
                                    )
                                );
                }
            }
        }
    }
}
8
Bernard Badenhorst

Vous pouvez utiliser le code de ce projet expliqué dans cet article pour créer un attribut ExpectedExceptionMessage qui fonctionnera avec MS Test pour obtenir le résultat souhaité.

le test ms ( échoue ):

[TestClass]
public class Tests : MsTestExtensionsTestFixture
{
    [TestMethod, ExpectedExceptionMessage(typeof(System.FormatException), "blah")]
    public void Validate()
    {
        int.Parse("dfd");
    }
}
4
CRice

J'ai écrit cela il y a quelque temps, alors peut-être qu'il existe une meilleure façon dans VS2012.

http://dripcode.blogspot.com.au/search?q=exception

1
John Roth

Essaye ça. Dans cet exemple, j'ai un message d'accueil qui affiche le message d'accueil pour un nom donné. Lorsque le paramètre name est vide ou null, le système lève une exception avec un message. Le ExceptionAssert.Throws vérifiez les deux dans MsTest.

[TestMethod]
public void Does_Application_Display_Correct_Exception_Message_For_Empty_String()
{
    // Arrange
    var oHelloWorld = new HelloWorld();

    // Act

    // Asset

    ExceptionAssert.Throws<ArgumentException>(() => 
            oHelloWorld.GreetingMessge(""),"Invalid Name, Name can't be empty");
}

[TestMethod]
public void Does_Application_Display_Correct_Exception_Message_For_Null_String()
{
    // Arrange
    var oHelloWorld = new HelloWorld();

    // Act

    // Asset

    ExceptionAssert.Throws<ArgumentNullException>(() => 
        oHelloWorld.GreetingMessge(null), "Invalid Name, Name can't be null");
}
0
trendvirtual