2009-12-22 6 views
30

Verwenden von MSTest wie kann ich die genaue Fehlermeldung überprüfen, die von einer Testmethode kommt? Ich weiß, [ExpectedException(typeof(ApplicationException), error msg)] vergleicht nicht die Fehlermeldung von meiner Testmethode, obwohl in anderen Unit-Test-Framework es tut.In MSTest, wie kann ich genaue Fehlermeldung mithilfe von [ExpectedException (typeof (ApplicationException))] überprüfen

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, meinen Komponententest mit einem try catch-Block zu schreiben, aber ich muss wieder 4 Zeilen schreiben.

Gibt es eine klügste Möglichkeit, die Fehlermeldung zu überprüfen.

Cheers, Pritam

+0

Fest Titel:

public static class Catch { public static Exception Exception(Action action) { Exception exception = null; try { action(); } catch (Exception ex) { exception = ex; } return exception; } } 

Auf diese Weise können Sie tun. Wusste nicht, MSTest hatte das nicht ... sollte einfach zu unterstützen sein – Gishu

Antwort

0

Mit MSTest, können Sie dies nicht tun.

Sie kennen bereits die Lösung für dieses Problem: Setzen Sie die Nachricht einer Ausnahme in einem catch-Block.

-1

Update: Ups .. sehen, dass Sie dies in MSTest wollen. Es tut uns leid. Geschwindigkeit lesen & Irre von Ihrem Titel.

Versuchen Sie diese Erweiterungsprojekt von Callum Hibbert und sehen, ob es funktioniert.

Alte Antwort:

Sie können dies tun, mit NUnit 2.4 und höher. Siehe documentation von ExpectedException hier

[ExpectedException(typeof(ArgumentException), ExpectedMessage="unspecified", MatchType=MessageMatch.Contains)] 
public void TestMethod() 
{ 
... 

Keyword-Option Exakt sein kann (Standard), Enthält oder Regex .. die so ziemlich übernimmt die 80% Use-Case. Es gibt auch eine erweiterte Methode der Exception-Handler-Methode, wenn die Verifizierung zu komplex wird. Sie wurde nie persönlich verwendet. Sie brauchte sie noch nicht.

0

MbUnit kann auch dies tun:

[Test] 
[Row(ExpectedExceptionMessage="my message")] 
void TestBlah(... 
4

In MSTest gibt es keine integrierte Möglichkeit, es zu tun. Das ist etwa so ‚elegant‘ wie es geht:

[TestMethod] 
public void Test8() 
{ 
    var t = new Thrower(); 
    try 
    { 
     t.DoStuffThatThrows(); 
     Assert.Fail("Exception expected."); 
    } 
    catch (InvalidOperationException e) 
    { 
     Assert.AreEqual("Boo hiss!", e.Message); 
    } 
} 

Sie könnten jedoch xUnit.NET die Assert.Throws API, um eine benutzerdefinierte Bibliothek Portierung betrachten - das ist, was wir getan haben.

Sie können auch zu Microsoft Connect eine vote on this suggestion gehen.

15

Verwenden Sie diese kleine Hilfsklasse:

public static class ExceptionAssert 
{ 
    public static void Throws<TException>(Action action, string message) 
     where TException : Exception 
    { 
     try 
     { 
      action(); 

      Assert.Fail("Exception of type {0} expected; got none exception", typeof(TException).Name); 
     } 
     catch (TException ex) 
     { 
      Assert.AreEqual(message, ex.Message); 
     } 
     catch (Exception ex) 
     { 
      Assert.Fail("Exception of type {0} expected; got exception of type {1}", typeof(TException).Name, ex.GetType().Name);    
     } 
    } 
} 

Verbrauch:

Foo foo = new Foo(); 
foo.Property = 42; 

ExceptionAssert.Throws<InvalidOperationException>(() => foo.DoSomethingCritical(), "You cannot do anything when Property is 42."); 

Der Vorteil der expliziten fangen Ausnahmen ist, dass teh Test nicht erfolgreich ist, wenn ein anderes Mitglied (zB bei der Initialisierung) die Würfe Ausnahme.

+0

Nice! Ich werde Ihre Methode verwenden und erweitern, um die ** InnerException ** geltend zu machen: D –

+0

Sollte nicht die erste Assert.Fail am Ende sein, außerhalb der Try/Catch-Block? Wenn Sie es in den try-Block setzen, wird es vom zweiten catch-Block abgefangen. Das verursacht zwei Ausnahmen. – Rhyous

+0

@Rhyous Die Lösung für die Assert.Fail ist das folgende als ersten Catch-Block hinzufügen catch (AssertFailedException) {throw; } –

4

Fluent Assertions (erhältlich in NuGet) hat eine sehr „Sprache natürliche“ Syntax für die Erwartungen in Unit-Tests zu definieren:

objectundertest.Invoking(o => o.MethodUnderTest()).ShouldThrow<ExpectedException>() 
    .WithMessage("the expected error message"); 

Es gibt mehrere Varianten zur Überprüfung der Fehlermeldung mit einem beliebigen Algorithmus (Where(e => ...) sowie Überprüfung auf innere Ausnahmen und ihre Nachrichten.

5

Ich suchte nach einer Möglichkeit, die Anwesenheit und den Typ der inneren Ausnahme mit Mstest zu überprüfen, und ich habe diese Frage gefunden. Ich kenne es ein 2 Jahre altes Thema, aber da meine Lösung nicht hier ist, lass es mich teilen.

Für mich ist die eleganteste Möglichkeit, das Problem zu lösen, ist ein abgeleitetes Attribut zu erstellen, hier ist meins (sorry, aber Kommentare und Strings sind in französisch, meine natürliche Sprache, aber es sollte klar sein):

#region Références 
using System; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System.Text.RegularExpressions; 
#endregion 

namespace MsTestEx 
{ 
    /// <summary> 
    /// Extention de l'attribut ExpectedException permettant de vérifier plus d'éléments (Message, InnerException, ...) 
    /// </summary> 
    public class ExpectedExceptionEx 
     : ExpectedExceptionBaseAttribute 
    { 
     #region Variables locales 
     private Type _ExpectedException    = null; 
     private string _ExpectedMessage    = null; 
     private Type _ExpectedInnerException   = null; 
     private string _ExpectedInnerExceptionMessage = null; 
     private bool _IsExpectedMessageRegex   = false; 
     private bool _IsExpectedInnerMessageRegex = false; 
     private bool _AllowDerivedType    = false; 
     private bool _AllowInnerExceptionDerivedType = false; 

     private bool _CheckExpectedMessage   = false; 
     private bool _CheckInnerExceptionType  = false; 
     private bool _CheckInnerExceptionMessage  = false; 
     #endregion 

     #region Propriétés 
     /// <summary> 
     /// Vérifie que le message de l'exception correspond à celui-ci. 
     /// </summary> 
     public string ExpectedMessage 
     { 
      get { return _ExpectedMessage; } 
      set { _ExpectedMessage = value; _CheckExpectedMessage = true; } 
     } 

     /// <summary> 
     /// Vérifie que le message de l'inner-exception correspond à celui-ci. 
     /// </summary> 
     public string ExpectedInnerExceptionMessage 
     { 
      get { return _ExpectedInnerExceptionMessage; } 
      set { _ExpectedInnerExceptionMessage = value; _CheckInnerExceptionMessage = true; } 
     } 

     /// <summary> 
     /// Vérifie que l'exception possède bien une inner-exception du type spécifié. 
     /// Spécifier "null" pour vérifier l'absence d'inner-exception. 
     /// </summary> 
     public Type ExpectedInnerException 
     { 
      get { return _ExpectedInnerException; } 
      set { _ExpectedInnerException = value; _CheckInnerExceptionType = true; } 
     } 

     /// <summary> 
     /// Indique si le message attendu est exprimé via une expression rationnelle. 
     /// </summary> 
     public bool IsExpectedMessageRegex 
     { 
      get { return _IsExpectedMessageRegex; } 
      set { _IsExpectedMessageRegex = value; } 
     } 

     /// <summary> 
     /// Indique si le message attendu de l'inner-exception est exprimé via une expression rationnelle. 
     /// </summary> 
     public bool IsExpectedInnerMessageRegex 
     { 
      get { return _IsExpectedInnerMessageRegex; } 
      set { _IsExpectedInnerMessageRegex = value; } 
     } 

     /// <summary> 
     /// Indique si les exceptions dérivées sont acceptées. 
     /// </summary> 
     public bool AllowDerivedType 
     { 
      get { return _AllowDerivedType; } 
      set { _AllowDerivedType = value; } 
     } 

     /// <summary> 
     /// Indique si les inner-exceptions dérivées sont acceptées. 
     /// </summary> 
     public bool AllowInnerExceptionDerivedType 
     { 
      get { return _AllowInnerExceptionDerivedType; } 
      set { _AllowInnerExceptionDerivedType = value; } 
     } 
     #endregion 

     #region Constructeurs 
     /// <summary> 
     /// Indique le type d'exception attendu par le test. 
     /// </summary> 
     /// <param name="expectedException">Type de l'exception attendu.</param> 
     public ExpectedExceptionEx(Type expectedException) 
     { 
      _ExpectedException = expectedException; 
     } 
     #endregion 

     #region Méthodes 
     /// <summary> 
     /// Effectue la vérification. 
     /// </summary> 
     /// <param name="exception">Exception levée.</param> 
     protected override void Verify(Exception exception) 
     { 
      Assert.IsNotNull(exception); // Pas eu d'exception, ce n'est pas normal 

      // Vérification du type de l'exception 
      Type actualType = exception.GetType(); 
      if (_AllowDerivedType) Assert.IsTrue(_ExpectedException.IsAssignableFrom(actualType), "L'exception reçue n'est pas du type spécifié ni d'un type dérivé."); 
      else Assert.AreEqual(_ExpectedException, actualType, "L'exception reçue n'est pas du type spécifié."); 

      // Vérification du message de l'exception 
      if (_CheckExpectedMessage) 
      { 
       if (_IsExpectedMessageRegex) 
        Assert.IsTrue(Regex.IsMatch(exception.Message, _ExpectedMessage), "Le message de l'exception ne correspond pas à l'expression rationnelle"); 
       else 
       { 
        string s1, s2; 
        if (exception.Message.Length > _ExpectedMessage.Length) 
        { 
         s1 = exception.Message; 
         s2 = _ExpectedMessage; 
        } 
        else 
        { 
         s1 = _ExpectedMessage; 
         s2 = exception.Message; 
        } 
        Assert.IsTrue(s1.Contains(s2), "Le message de l'exception ne contient pas et n'est pas contenu par le message attendu."); 
       } 
      } 

      if (_CheckInnerExceptionType) 
      { 
       if (_ExpectedInnerException == null) Assert.IsNotNull(exception.InnerException); 
       else 
       { 
        // Vérification du type de l'exception 
        actualType = exception.InnerException.GetType(); 
        if (_AllowInnerExceptionDerivedType) Assert.IsTrue(_ExpectedInnerException.IsAssignableFrom(actualType), "L'inner-exception reçue n'est pas du type spécifié ni d'un type dérivé."); 
        else Assert.AreEqual(_ExpectedInnerException, actualType, "L'inner-exception reçue n'est pas du type spécifié."); 
       } 
      } 

      if (_CheckInnerExceptionMessage) 
      { 
       Assert.IsNotNull(exception.InnerException); 
       if (_IsExpectedInnerMessageRegex) 
        Assert.IsTrue(Regex.IsMatch(exception.InnerException.Message, _ExpectedInnerExceptionMessage), "Le message de l'exception ne correspond pas à l'expression rationnelle"); 
       else 
       { 
        string s1, s2; 
        if (exception.InnerException.Message.Length > _ExpectedInnerExceptionMessage.Length) 
        { 
         s1 = exception.InnerException.Message; 
         s2 = _ExpectedInnerExceptionMessage; 
        } 
        else 
        { 
         s1 = _ExpectedInnerExceptionMessage; 
         s2 = exception.InnerException.Message; 
        } 
        Assert.IsTrue(s1.Contains(s2), "Le message de l'inner-exception ne contient pas et n'est pas contenu par le message attendu."); 
       } 
      } 
     } 
     #endregion 
    } 
} 

Verwenden Sie dieses Attribut jetzt mit benannten Parametern anstelle von "ExpectedException". Mit meinem Attribut können Sie prüfen, ob es eine innere Ausnahme gibt, Nachricht der Ausnahme und innere Ausnahme, verwenden Sie eine Regex, um Nachrichten zu entsprechen, etc ... Sie können anpassen, wie Sie wollen.

+0

Danke für das Teilen :) – Anne

31

Sie können create your own ExpectedException attribute wo können Sie Assert die Nachricht der Exception, die geworfen wurde.

-Code

namespace TestProject 
{ 
    public sealed class MyExpectedException : ExpectedExceptionBaseAttribute 
    { 
     private Type _expectedExceptionType; 
     private string _expectedExceptionMessage; 

     public MyExpectedException(Type expectedExceptionType) 
     { 
      _expectedExceptionType = expectedExceptionType; 
      _expectedExceptionMessage = string.Empty; 
     } 

     public MyExpectedException(Type expectedExceptionType, string expectedExceptionMessage) 
     { 
      _expectedExceptionType = expectedExceptionType; 
      _expectedExceptionMessage = expectedExceptionMessage; 
     } 

     protected override void Verify(Exception exception) 
     { 
      Assert.IsNotNull(exception); 

      Assert.IsInstanceOfType(exception, _expectedExceptionType, "Wrong type of exception was thrown."); 

      if(!_expectedExceptionMessage.Length.Equals(0)) 
      { 
       Assert.AreEqual(_expectedExceptionMessage, exception.Message, "Wrong exception message was returned."); 
      } 
     } 
    } 
} 

Nutzungs

[TestMethod] 
[MyExpectedException(typeof(Exception), "Error")] 
public void TestMethod() 
{ 
    throw new Exception("Error"); 
} 
+1

Ich mag es ... wirklich nette Art der Suche nach benutzerdefinierten Ausnahmemeldungen. :) –

0

Der Ärger mit Anmerkungen und try/catch-Blöcke sind, dass Sie Phasen keine saubere Trennung zwischen dem ACT und ASSERT der Test. Eine einfachere appraoch ist die Ausnahme als Teil der ACT-Phase „erfassen“, um eine utitlity Routine wie die Verwendung von:

// ACT 
var actualException = Catch.Exception(() => DoSomething()) 

// ASSERT 
Assert.IsNotNull(actualException, "No exception thrown"); 
Assert.IsInstanceOfType(actualException, expectedType); 
Assert.AreEqual(expectedExceptionMessage, actualException.Message); 
Verwandte Themen