Domanda

Come faccio a utilizzare Assert (o altra classe di Test?) per verificare che l'eccezione è stata generata?

È stato utile?

Soluzione

Per "Visual Studio Team Test" Sembra si applica l'attributo ExpectedException il metodo del test.

Esempio dalla documentazione qui: A Test Unità Soluzione con Visual Studio team test

[TestMethod]
[ExpectedException(typeof(ArgumentException),
    "A userId of null was inappropriately allowed.")]
public void NullUserIdInConstructor()
{
   LogonInfo logonInfo = new LogonInfo(null, "P@ss0word");
}

Altri suggerimenti

Di solito il vostro ambiente di test avrà una risposta per questo. Ma se non è abbastanza flessibile, si può sempre fare questo:

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // If it gets to this line, no exception was thrown
} catch (GoodException) { }

Come @Jonas sottolinea, questo non funziona per la cattura di un Eccezione di base:

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // raises AssertionException
} catch (Exception) {
    // Catches the assertion exception, and the test passes
}

Se si deve assolutamente prendere delle eccezioni, è necessario rigenerare l'Assert.Fail (). Ma in realtà, questo è un segno che non dovrebbe essere questo-scrittura a mano; controllare il framework di test per le opzioni, o vedere se è possibile lanciare un'eccezione più significativa per verificare.

catch (AssertionException) { throw; }

Si dovrebbe essere in grado di adattare questo approccio a quello che ti piace - tra cui specificare quali tipi di eccezioni per la cattura. Se ci si aspetta solo determinati tipi, finisci i blocchi catch via con:

} catch (GoodException) {
} catch (Exception) {
    // not the right kind of exception
    Assert.Fail();
}

Il mio metodo preferito per l'attuazione del presente è quello di scrivere un metodo chiamato tiri liberi, e utilizzarlo come qualsiasi altro metodo Assert. Purtroppo, .NET non consente di scrivere un metodo di estensione statico, quindi non è possibile utilizzare questo metodo, come se in realtà appartiene alla costruzione in classe Assert; basta fare un altro chiamato MyAssert o qualcosa di simile. La classe si presenta così:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        public static void Throws<T>( Action func ) where T : Exception
        {
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }

            if ( !exceptionThrown )
            {
                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but not thrown", typeof(T))
                    );
            }
        }
    }
}

Ciò significa che il vostro unit test è simile al seguente:

[TestMethod()]
public void ExceptionTest()
{
    String testStr = null;
    MyAssert.Throws<NullReferenceException>(() => testStr.ToUpper());
}

Quali sembra e si comporta molto più simile al resto della vostra sintassi di unit test.

Se stai usando MSTest, che in origine non aveva un attributo ExpectedException, si potrebbe fare questo:

try 
{
    SomeExceptionThrowingMethod()
    Assert.Fail("no exception thrown");
}
catch (Exception ex)
{
    Assert.IsTrue(ex is SpecificExceptionType);
}

se si utilizza NUnit, si può fare qualcosa di simile:

Assert.Throws<ExpectedException>(() => methodToTest());


E 'anche possibile memorizzare l'eccezione generata al fine di validare ulteriormente:

ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest());
Assert.AreEqual( "Expected message text.", ex.Message );
Assert.AreEqual( 5, ex.SomeNumber);

See: http://nunit.org/docs/2.5/exceptionAsserts.html

Diffidare dell'utilizzo ExpectedException, in quanto può portare a diverse insidie, come mostrato qui:

http://geekswithblogs.net/sdorman/archive/2009/01/17/unit-testing-and-expected-exceptions.aspx

E qui:

http://xunit.github.io/docs/comparisons.html

Se avete bisogno di test per le eccezioni, ci sono meno di buon occhio modi.È possibile utilizzare il try{agire/non}catch{assert} metodo, che può essere utile per i quadri che non hanno il supporto diretto per eccezione test diversi ExpectedException.

Un'alternativa migliore è utilizzare xUnit.NET che è molto moderna che guarda al futuro, ed estensibile test di unit quadro che ha imparato da tutti gli altri errori, e migliorato.Un tale miglioramento è da far Valere.Getta, che fornisce un molto meglio la sintassi per far valere eccezioni.

Si possono trovare xUnit.NET su github: http://xunit.github.io/

In un progetto sto lavorando su noi abbiamo un'altra soluzione facendo questo.

Per prima cosa Io non come l'ExpectedExceptionAttribute becuase ci vuole in considerazione che chiamata di metodo che ha causato l'eccezione.

Lo faccio con un helpermethod invece.

test

[TestMethod]
public void AccountRepository_ThrowsExceptionIfFileisCorrupt()
{
     var file = File.Create("Accounts.bin");
     file.WriteByte(1);
     file.Close();

     IAccountRepository repo = new FileAccountRepository();
     TestHelpers.AssertThrows<SerializationException>(()=>repo.GetAll());            
}

HelperMethod

public static TException AssertThrows<TException>(Action action) where TException : Exception
    {
        try
        {
            action();
        }
        catch (TException ex)
        {
            return ex;
        }
        Assert.Fail("Expected exception was not thrown");

        return null;
    }

Ordinato, purtroppo non si è;)

MSTest (v2) ha ora una funzione Assert.ThrowsException che può essere utilizzato in questo modo:

Assert.ThrowsException<System.FormatException>(() =>
            {
                Story actual = PersonalSite.Services.Content.ExtractHeader(String.Empty);
            }); 

È possibile installarlo con NuGet: Install-Package MSTest.TestFramework

Si tratta di un attributo sul metodo di prova ... non si usa Assert. Sembra che questo:

[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()

È possibile scaricare un pacchetto da Nuget utilizzando: PM> Installa-Package MSTestExtensions che aggiunge Assert.Throws () sintassi nello stile di NUnit / xUnit a MSTest.

istruzioni ad alto livello:. Scarica il montaggio e ereditare da BaseTest ed è possibile utilizzare le Assert.Throws () sintassi

Il metodo principale per l'implementazione Getta appare come segue:

public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
{
    try
    {
        task();
    }
    catch (Exception ex)
    {
        AssertExceptionType<T>(ex);
        AssertExceptionMessage(ex, expectedMessage, options);
        return;
    }

    if (typeof(T).Equals(new Exception().GetType()))
    {
        Assert.Fail("Expected exception but no exception was thrown.");
    }
    else
    {
        Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
    }
}

Disclosure: ho messo insieme questo pacchetto

.

Più informazioni: http: // www .bradoncode.com / blog / 2012/01 / asserendo-eccezioni-in-mstest-with.html

È possibile raggiungere questo obiettivo con un semplice una riga.

Se il foo.bar() operazione è asincrona:

await Assert.ThrowsExceptionAsync<Exception>(() => foo.bar());

Se foo.bar() non è asincrona

Assert.ThrowsException<Exception>(() => foo.bar());

Non consiglio usando l'attributo ExpectedException (dal momento che è troppo vincolante e soggetto a errori) o scrivere un blocco try / catch in ciascuna prova (dal momento che è troppo complicato e soggetto a errori). Utilizzare un metodo assert ben progettato - sia fornito dal proprio framework di test o lascia la tua. Ecco quello che ho scritto e l'uso.

public static class ExceptionAssert
{
    private static T GetException<T>(Action action, string message="") where T : Exception
    {
        try
        {
            action();
        }
        catch (T exception)
        {
            return exception;
        }
        throw new AssertFailedException("Expected exception " + typeof(T).FullName + ", but none was propagated.  " + message);
    }

    public static void Propagates<T>(Action action) where T : Exception
    {
        Propagates<T>(action, "");
    }

    public static void Propagates<T>(Action action, string message) where T : Exception
    {
        GetException<T>(action, message);
    }

    public static void Propagates<T>(Action action, Action<T> validation) where T : Exception
    {
        Propagates(action, validation, "");
    }

    public static void Propagates<T>(Action action, Action<T> validation, string message) where T : Exception
    {
        validation(GetException<T>(action, message));
    }
}

Esempio utilizza:

    [TestMethod]
    public void Run_PropagatesWin32Exception_ForInvalidExeFile()
    {
        (test setup that might propagate Win32Exception)
        ExceptionAssert.Propagates<Win32Exception>(
            () => CommandExecutionUtil.Run(Assembly.GetExecutingAssembly().Location, new string[0]));
        (more asserts or something)
    }

    [TestMethod]
    public void Run_PropagatesFileNotFoundException_ForExecutableNotFound()
    {
        (test setup that might propagate FileNotFoundException)
        ExceptionAssert.Propagates<FileNotFoundException>(
            () => CommandExecutionUtil.Run("NotThere.exe", new string[0]),
            e => StringAssert.Contains(e.Message, "NotThere.exe"));
        (more asserts or something)
    }

NOTE

Tornando eccezione invece di sostenere un callback di convalida è un'idea ragionevole se non che così facendo rende la sintassi di chiamata di questa asserzione molto diverso rispetto alle altre afferma che uso.

A differenza di altri, io uso 'propaga' invece di 'getta' da quando siamo in grado di verificare solo se un'eccezione si propaga da una chiamata. Non possiamo testare direttamente che viene generata un'eccezione. Ma suppongo che si possa immagine getta a significare:. Gettato e non catturato

FINALE PENSIERO

Prima di passare a questo tipo di approccio ho considerato usando l'attributo ExpectedException quando un test verificato soltanto il tipo e utilizzando un blocco try / catch se è richiesto più validazione. Ma, non solo avrei dovuto pensare a quale tecnica da utilizzare per ogni test, ma cambiando il codice da una tecnica all'altra come le esigenze cambiato non ero sforzo banale. Utilizzando uno approccio coerente salva sforzo mentale.

Quindi, in sintesi, questo approccio sport:. Facilità d'uso, flessibilità e robustezza (difficile farlo sbagliato)

L'helper fornito da @Richiban sopra grandi opere tranne che non gestisce la situazione in cui viene generata un'eccezione, ma non il tipo previsto. I seguenti indirizzi:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        /// <summary>
        /// Helper for Asserting that a function throws an exception of a particular type.
        /// </summary>
        public static void Throws<T>( Action func ) where T : Exception
        {
            Exception exceptionOther = null;
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }
            catch (Exception e) {
                exceptionOther = e;
            }

            if ( !exceptionThrown )
            {
                if (exceptionOther != null) {
                    throw new AssertFailedException(
                        String.Format("An exception of type {0} was expected, but not thrown. Instead, an exception of type {1} was thrown.", typeof(T), exceptionOther.GetType()),
                        exceptionOther
                        );
                }

                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but no exception was thrown.", typeof(T))
                    );
            }
        }
    }
}

Dal momento che si parla con altre classi di test, una scelta migliore rispetto l'attributo ExpectedException è quello di utilizzare Shoudly ' s Should.Throw .

Should.Throw<DivideByZeroException>(() => { MyDivideMethod(1, 0); });

Diciamo che abbiamo un requisito che il cliente deve avere un Indirizzo per creare un ordine . In caso contrario, il metodo CreateOrderForCustomer deve tradursi in un ArgumentException. Poi potremmo scrivere:

[TestMethod]
public void NullUserIdInConstructor()
{
  var customer = new Customer(name := "Justin", address := null};

  Should.Throw<ArgumentException>(() => {
    var order = CreateOrderForCustomer(customer) });
}

Questo è meglio che usare un attributo ExpectedException perché noi stiamo essendo specifiche su quello che dovrebbe lanciare l'errore. Questo rende i requisiti nei nostri test più chiari e rende anche la diagnosi più facile quando il test fallisce.

Nota c'è anche un Should.ThrowAsync per il test metodo asincrono.

In alternativa si può provare a testare le eccezioni sono infatti essere gettato con i prossimi 2 linee il test.

var testDelegate = () => MyService.Method(params);
Assert.Throws<Exception>(testDelegate);

Beh io più o meno riassumere quanto chiunque altro qui ha detto prima ... In ogni modo, ecco il codice ho costruito secondo le buone risposte :) Tutto resta da fare è copiare e uso ...

/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException.
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="methodToExecute">The method to execute to generate the exception.</param>
public static void AssertRaises<TException>(Action methodToExecute) where TException : System.Exception
{
    try
    {
        methodToExecute();
    }
    catch (TException) {
        return;
    }  
    catch (System.Exception ex)
    {
        Assert.Fail("Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
    }
    Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");  
}

In VS built-in unità di test se si vuole semplicemente verificare che "qualsiasi eccezione" è gettato, ma non si conosce il tipo, è possibile utilizzare un fermo tutto:

[TestMethod]
[ExpectedException(typeof(Exception), AllowDerivedTypes = true)]
public void ThrowExceptionTest()
{
    //...
}

NUnit Documenti per gli esempi su:

[ExpectedException( typeof( ArgumentException ) )]

Si tratta di andare a dipendere da ciò framework di test stai usando?

In MbUnit, ad esempio, è possibile specificare l'eccezione previsto con un attributo per garantire che si stanno ottenendo l'eccezione si aspetta davvero.

[ExpectedException(typeof(ArgumentException))]

Nel caso di utilizzo di NUnit , provate questo:

Assert.That(() =>
        {
            Your_Method_To_Test();
        }, Throws.TypeOf<Your_Specific_Exception>().With.Message.EqualTo("Your_Specific_Message"));

Anche se questa è una vecchia questione, vorrei aggiungere un nuovo pensiero alla discussione. Ho esteso Arrange, Act, assert modello da aspettarsi, arrangiare, Act, Assert. È possibile effettuare un puntatore un'eccezione prevista, quindi affermare che è stato assegnato al. Questo si sente più pulito di fare il vostro afferma in un blocco catch, lasciando la sezione legge per lo più solo per l'una riga di codice per chiamare il metodo in prova. Inoltre non è necessario Assert.Fail(); o return da più punti del codice. Qualsiasi altra eccezione generata causerà il fallimento del test, perché non sarà catturato, e se viene generata un'eccezione del vostro tipo previsto, ma il che non era quello che ti aspettavi, affermando contro il messaggio o di altre proprietà di l'eccezione contribuire a rendere sicuro il test non passerà inavvertitamente.

[TestMethod]
public void Bar_InvalidDependency_ThrowsInvalidOperationException()
{
    // Expectations
    InvalidOperationException expectedException = null;
    string expectedExceptionMessage = "Bar did something invalid.";

    // Arrange
    IDependency dependency = DependencyMocks.Create();
    Foo foo = new Foo(dependency);

    // Act
    try
    {
        foo.Bar();
    }
    catch (InvalidOperationException ex)
    {
        expectedException = ex;
    }

    // Assert
    Assert.IsNotNull(expectedException);
    Assert.AreEqual(expectedExceptionMessage, expectedException.Message);
}

C'è una libreria impressionante chiamato NFluent che accelera e facilita il modo in cui scrivere le vostre affermazioni .

E 'abbastanza semplice da scrivere un'affermazione per un'eccezione:

    [Test]
    public void given_when_then()
    {
        Check.ThatCode(() => MethodToTest())
            .Throws<Exception>()
            .WithMessage("Process has been failed");
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top