Özel durumun türünü iddia etmek için Assert.Throws'u nasıl kullanabilirim?


247

Assert.ThrowsKural dışı durumun türünü ve gerçek ileti ifadelerini iddia etmek için nasıl kullanılır ?

Bunun gibi bir şey:

Assert.Throws<Exception>(
    ()=>user.MakeUserActive()).WithMessage("Actual exception message")

Test ettiğim yöntem, farklı iletilerle aynı türden birden çok ileti atar ve içeriğe bağlı olarak doğru iletinin atılmasını sınamanın bir yoluna ihtiyacım var.

Yanıtlar:


444

Assert.Throws atılan istisnayı döndürür.

var ex = Assert.Throws<Exception>(() => user.MakeUserActive());
Assert.That(ex.Message, Is.EqualTo("Actual exception message"));

Dolayısıyla, herhangi bir istisna atılmazsa veya yanlış türde bir istisna atılırsa, ilk Assert.Throwsiddia başarısız olur. Ancak, doğru türde bir istisna atılırsa, şimdi değişkene kaydettiğiniz gerçek istisna hakkında iddia edebilirsiniz.

Bu kalıbı kullanarak, istisna mesajından başka şeyler üzerinde iddia edebilirsiniz, örneğin ArgumentExceptionve türevlerde, parametre adının doğru olduğunu iddia edebilirsiniz:

var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null));
Assert.That(ex.ParamName, Is.EqualTo("bar"));

Akıcı API'yı şu önerileri yapmak için de kullanabilirsiniz:

Assert.That(() => foo.Bar(null), 
Throws.Exception
  .TypeOf<ArgumentNullException>()
  .With.Property("ParamName")
  .EqualTo("bar"));

Veya alternatif olarak

Assert.That(
    Assert.Throws<ArgumentNullException>(() =>
        foo.Bar(null)
    .ParamName,
Is.EqualTo("bar"));

İstisna mesajlar konusunda küçük bir ipucu SetCultureAttribute, atılan mesajın beklenen kültürü kullandığından emin olmak için test yöntemini ile süslemektir . İstisna mesajlarınızı yerelleştirmeye izin verecek kaynaklar olarak saklarsanız bu devreye girer.


Bu benim için gerçekten yararlı oldu - Hatayı görüntülemek için bir yol istedim, Assert.Throws yöntemi tarafından bir değer döndürüldüğünde bile okumadım. Teşekkürler
Haroon

6
+1 Akıcı API'yı gösterdiğiniz için teşekkür ederiz, bazı nedenlerden dolayı yalnızca NUnit belgelerinden nasıl kullanılacağını anlayabiliyordum.
aolszowka

İletiyi onaylamak istediğinizde, "Özellik" yerine doğrudan Message özelliğini de kullanabilirsiniz.
Marcel

25

Artık ExpectedExceptionözellikleri kullanabilirsiniz , ör.

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}

2
Bu ilk gördüğümde beni biraz rahatsız etti, çünkü test görünüşünün hiçbir iddiası yoktu, bu benim için bir koku idi. Bu güzel bir özellik, ancak ekipte bu özelliğin Assert üzerinde kullanılmasının gerekeceği tartışılmalı. Throws
Marcel

14
+1 da istisnaları test etmenin güzel bir yoludur. Bu konuda akılda tutulması gereken tek şey, teorik olarak, bu mesajla InvalidOperationException özelliğindeki herhangi bir kod satırının, test verilerinizi / nesnelerini hazırlayan kodunuz veya testten önce yürütmeniz gereken herhangi bir yöntem de dahil olmak üzere testi geçeceğidir. test etmekle ilgilenen biri, muhtemelen yanlış bir pozitif sonuç verir. Elbette, bu mesajın ne kadar özel olduğuna ve test ettiğiniz istisna türüne bağlıdır. İle Assert.Throwtam olarak ilgilendiğiniz hattı hedefleyebilirsiniz.
Hayır

21
ExpectedException özelliği NUnit 3'te kullanımdan kaldırıldı: github.com/nunit/docs/wiki/Breaking-Changes
Frank

13
Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));

2
Operatör nameof tanıtımı ile ben bu mükemmel anwser düzenlemek için:Assert.That(myTestDelegate, Throws.ArgumentException .With.Property(nameof(ArgumentException.Message)).EqualTo("your argument is invalid."));
Samuel

@Samuel Bu düzenleme güzel yazılmış güçlü bir başvuru kullanır, ancak diğer taraftan, son derece düşük bir karmaşa adıdır ve sihirli dize akıcılığı geliştirir. Sanırım lezzet meselesi
Jordan Morris

1
Size tamamen katılıyorum Exception.Message. Yine de en azından bu alternatifi eklemenizi tavsiye ederim çünkü With.Propertydiğer nesnelerde de kullanılabilir, bu durumda kodun kararlılığını artıracaktır.
Samuel

5

Bu, eski çözümü de içeren eski ve alakalı bir sorudur, bu yüzden mevcut çözümü ekliyorum:

public void Test() {
    throw new MyCustomException("You can't do that!");
}

[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
    var exception = Assert.ThrowsException<MyCustomException>(
        () => Test(),
        "This should have thrown!");
    Assert.AreEqual("You can't do that!", exception.Message);
}

İle çalışır using Microsoft.VisualStudio.TestTools.UnitTesting;


Bir yöntemin JUnit'teki gibi bir istisna oluşturduğunu iddia etmenin kısa bir yolu olmadığına gerçekten şaşırdım. Farkında olmadığım imalar olmadıkça, bu muhtemelen şu anda en alakalı cevaptır.
NetherGranite

3

Kalıcı yanıtı genişletmek ve NUnit'in daha fazla işlevselliğini sağlamak için şunları yapabilirsiniz:

public bool AssertThrows<TException>(
    Action action,
    Func<TException, bool> exceptionCondition = null)
    where TException : Exception 
{
    try
    {
        action();
    }
    catch (TException ex)
    {
        if (exceptionCondition != null)
        {
            return exceptionCondition(ex);
        }

        return true;
    }
    catch
    {
        return false;
    }

    return false; 
}

Örnekler:

// No exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => {}));

// Wrong exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new ApplicationException(); }));

// Correct exception thrown - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException(); }));

// Correct exception thrown, but wrong message - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("ABCD"); },
        ex => ex.Message == "1234"));

// Correct exception thrown, with correct message - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("1234"); },
        ex => ex.Message == "1234"));

2

Bu sorunun ortaya çıkmasından bu yana uzun zaman geçti, anlıyorum, ama son zamanlarda aynı şeyle karşılaştım ve MSTest için bu işlevi öneriyorum:

public bool AssertThrows(Action action) where T : Exception 
{ 
try {action();} 
catch(Exception exception) 
{ 
    if (exception.GetType() == typeof(T)) return true; 
} 
return false; 
}

kullanımı:

Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); }));

Daha fazlası için: http://phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/


2

Bazı yeni NUnit modellerinin ayrıntılarından rahatsız olduğum için, kişisel olarak benim için daha temiz kod oluşturmak için böyle bir şey kullanıyorum:

public void AssertBusinessRuleException(TestDelegate code, string expectedMessage)
{
    var ex = Assert.Throws<BusinessRuleException>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception
{
    var ex = Assert.Throws<T>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

Kullanım sonra:

AssertBusinessRuleException(() => user.MakeUserActive(), "Actual exception message");

1
TestDelegate nedir?
reggaeguitar

1
Parametre olarak yürütmek için kodu geçirmenizi sağlar. NUnit çerçevesinde bir sınıftır (v3.2.0.0).
Savage
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.