【问题标题】:XUnit Assert.IsType() with multiple expected types具有多种预期类型的​​ XUnit Assert.IsType()
【发布时间】:2017-11-15 07:58:48
【问题描述】:

我需要检查三种可能的异常类型中的一种。如果其中之一被抛出测试应该成功完成。我在几个场景中使用[Theory][MemberData]

[Theory]
[MemberData(nameof(GetInvalidMimeMessages))]
public async Task ProcessAsync_TestFail(MimeMessage message)
{
    var stub = Mock.Of<IOptions<ScrapyardFilesOptions>>(s => s.Value.ConnectionString == "UseDevelopmentStorage=true" && s.Value.Container == "exchange");
    var loggerMock = new Mock<ILogger<ScrapyardFilesHandler>>(MockBehavior.Loose);
    var scrapyard = new ScrapyardFilesHandler(loggerMock.Object, stub);
    var ex = await Assert.ThrowsAnyAsync<Exception>(() => scrapyard.ProcessAsync(message));

    // imagine solution somehow like that
    Assert.IsType( 
                    { 
                      typeof(NullReferenceException)    ||
                      typeof(KeyNotFoundException)      ||
                      typeof(InvalidOperationException) ||
                    },
                    ex); 
}

private static IEnumerable<object[]> GetInvalidMimeMessages()
{
    yield return new object[] { null };
    yield return new object[] { new MimeMessage() };
    yield return new object[]
    {
        new MimeMessage(
            new List<InternetAddress>(),
            new InternetAddressList() { new MailboxAddress("ExchangeScrapyard@ol.su"), new MailboxAddress("exchange+scrapyard@Olex.su"), },
            string.Empty,
            MimeEntity.Load(ParserOptions.Default, Stream.Null))
    };
    yield return new object[]
    {
        new MimeMessage(
            new List<InternetAddress>(),
            new InternetAddressList() { new MailboxAddress("ExchangeOLC449@ol.su"), new MailboxAddress("exchange+olc@Ol.su"), },
            string.Empty,
            MimeEntity.Load(ParserOptions.Default, Stream.Null))
    };
}

我怎样才能得到这样的断言?

【问题讨论】:

  • 为什么不改用Assert.Throws
  • 为什么一个输入一个动作会导致多个异常?
  • 一条消息应该在一个异常中返回,因为现在您将多条消息传递到您的测试中,但您不知道哪条消息引发了哪个异常。
  • @CodeCaster 不确定我的理解是否正确,但我不应该知道哪条消息引发了哪个异常(其实我已经知道了
  • 是的,你应该这样做。您传递了四个不同的消息并期望三个不同的异常。您需要知道哪个消息导致哪个异常。如果 null 消息抛出 InvalidOperationException 怎么办?这是否意味着您的代码可以正常工作?

标签: c# unit-testing .net-core xunit.net


【解决方案1】:
var exceptions = new List<Type>()
            {
                typeof(NullReferenceException),
                typeof(KeyNotFoundException),
                typeof(InvalidOperationException),
            };

var ex = await Assert.ThrowsAnyAsync<Exception>(() => foo.Bar());
Assert.Contains(ex.GetType(), exceptions);

【讨论】:

  • 有趣的解决方案,但只适用于确切的类型,而不适用于派生的类型。但我认为这已经足够了,因为您不会从 NullReferenceException 或任何其他人那里获得。
  • 您可以使用反射的IsAssignableIsSubClass 来检查派生异常:stackoverflow.com/a/2742288/213550
【解决方案2】:

由于您有多个可能的异常要抛出,因此 NUnit 中没有内置方法来检查这一点。如果你只需要一个例外,你可以使用这个:

Assert.Throws<NullReferenceException>(() => DoSomething);

但是,如果有多个,您可以使用旧的 try-catch:

try
{
    DoSomething();
}
catch(NullReferenceException) { Assert.Pass(); }
catch(KeyNotFoundException) { Assert.Pass(); }
catch(InvalidOperationException) { Assert.Pass(); }
catch(Exception) { Assert.Fail("Unexpected exception was caught"); }
Assert.Fail("No exception was caught");

【讨论】:

  • 感谢您,Assert.Pass() 的有趣方式
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 2015-05-15
  • 2017-11-03
  • 2019-12-21
相关资源
最近更新 更多