简体   繁体   English

断言已引发处理的异常

[英]Assert a handled exception was thrown

I am handling several exceptions and not re-throwing them once handled. 我正在处理几个异常,并且一旦处理就不会重新抛出它们。 How can I assert the exception was invoked in my unit test. 如何断言在单元测试中调用了异常。

What I would do is create a custom Exception for your legacy code and place the exceptions thrown by your legacy stuff into it's inner exception. 我要做的是为您的遗留代码创建一个自定义Exception ,并将遗留的东西抛出的异常放入其内部异常中。 Then you can always swallow your custom exception to ignore them in your main app but then they'll still be thrown for your unit testing. 然后,您始终可以吞下自定义异常,以在主应用程序中忽略它们,但是它们仍将被抛出以进行单元测试。

Example: 例:

try
{
    //rubbish legacy code which will throw all kinds of exceptions
}
catch(Exception ex)
{
    throw new CustomException(message: "something bad happened", innerException: ex);
}

Then normally you can do the following: 然后通常可以执行以下操作:

try
{
    MethodWhichCallsRubbishLegacyStuffAndWillProbablyThrowException();
}
catch (CustomException c)
{
    //do nothing or better yet - logging!
}
catch (Exception ex)
{
    //handle potential exceptions caused elsewhere
}

Now in your unit test you can assert against the CustomException or indeed the specific InnerException which was thrown. 现在,在单元测试中,您可以针对CustomException或实际上引发的特定InnerException进行断言。

Based on your comment in your question: 根据您对问题的评论:

I am sending an email to first line support if one of my messages fails due to a legacy application interface which could throw many different exceptions for which I am handling. 如果我的一条消息由于遗留的应用程序界面而失败,这可能会引发我正在处理的许多不同异常,那么我将向第一线支持发送电子邮件。 It would be nice for my test to assert the exception was thrown and handled. 对于我的测试来说,断言该异常已被抛出并处理将是很好的。

The cleanest way to handle this is to make sure that the code that is handling the exceptions and then passing them on as an email receives the emailer as an Interface on your constructor. 解决此问题的最干净方法是确保处理异常然后将其作为电子邮件传递的代码在构造函数上将电子邮件发送者作为接口接收。

You can then mock the email handler, pass that to your code under test, and Assert that it was given the proper type of exception. 然后,您可以模拟电子邮件处理程序,将其传递给测试中的代码,然后断言已为其指定了适当的异常类型。

Something like this: 像这样:

public interface IExceptionEmailer {
    void HandleGenericException( Exception e );
    void HandleYourExceptionTypeA ( ExceptionTypeA e );
    // ... continue with your specific exceptions
}


public class YourClassThatCatchesExceptions( ){ 

    private IExceptionEmailer emailer;

    public void TheMethodThatCatches ( ) {

        try {
            // actions
        } catch ( ExceptionTypeA e ) {
            this.emailer.HandleYourExceptionTypeA( e );
        } catch ( Exception e ) {
            this.emailer.HandleGenericException( e );
        }
    }

    public YourClassThatCatchesExceptions( IExceptionEmailer emailer ) {
        this.emailer = emailer;
    }
}

Then your test class (assuming Moq and Xunit) would be: 然后您的测试类(假设Moq和Xunit)将是:

public class GivenAnExceptionEmailer ( ) {

    [Fact]
    public void WhenYourSpecificActionHappens ( ) {

        var emailer = new Mock<IExceptionEmailer>();
        // ARRANGE the rest of your system here
        var target = new YourClassThatCatchesExceptions( emailer.Object );


        // do whatever ACTions needed here to make it throw
        target.Whatever( );


        // then ASSERT that the emailer was given correct type
        // this will fail if the exception wasn't thrown or wasn't
        // properly caught and handled.
        emailer.Verify ( e => 
            e.HandleYourExceptionTypeA ( It.IsAny<ExceptionTypeA>( )),
            Times.Once( )
        );
    }    
}

I haven't tested that so you may find syntax issues, but, that isolates your system so that you can verify that the exact behavior you expect in YourClassThatCatchesExceptions fires (and your admins will thank you for not spamming them with a bunch of test emails!) 我没有进行过测试,因此您可能会发现语法问题,但是,这可以隔离您的系统,以便您可以验证您希望在YourClassThatCatchesExceptions触发的确切行为(并且您的管理员将感谢您不要向他们发送大量测试电子邮件, !)

I have done something like this, not sure its good practice or not... 我做过这样的事情,不确定它的好作法还是不行...

First: 第一:

[TestMethod]
public void MethodName_TestErrorMessage_When_SomeException()
{
  // Arrange
  const string ExpectedMessgae= "Error in Application ";
  this.MockedInterface.Setup(x=>x.MethodCall()).Throws<SomeException>();

  // Act
  var result=this.Controller.Action() as JsonResult;

  // Assert
  Assert.AreEqual(ExpectedMessage, result.Data.ToString());
}

This is just an example, but typically if you are not re-throwing exception and it has been handled in code, then we can verify that the message is correct or not. 这只是一个示例,但是通常,如果您不重新抛出异常并且已通过代码对其进行了处理,那么我们可以验证消息是否正确。 But this also implies at least you have not lost the stack trace in your code and returning it. 但这也意味着至少您没有丢失代码中的堆栈跟踪并返回它。 I will appreciate if someone helps me improving this. 如果有人帮助我改善这一点,我将不胜感激。 One other way is ExcpectedException Attribute, exception should not be handled for that. 另一种方法是ExcpectedException Attribute,不应为此处理异常。

Why care if nobody outside your code's gonna see it? 为什么不在乎代码之外的人看不到它呢? I wouldn't unit test such functionality which is not exposed to the callers. 我不会对未公开给调用者的功能进行单元测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM