【问题标题】:[ExpectedException(typeof(AnExceptionBaseException))][ExpectedException(typeof(AnExceptionBaseException))]
【发布时间】:2013-07-17 21:39:16
【问题描述】:

我编写了一个单元测试,它应该抛出AnExceptionAnotherException,两者都派生自AnExceptionBaseException。然后我继续为基本异常添加ExpectedExceptionAttribute,却发现我的测试仍将被标记为失败。

测试名称:Call_Should_Throw_If_Device_Is_Not_Ready 测试

...

结果消息:测试方法 DiskManagementTests.DiskFreeSpaceTests.Call_Should_Throw_If_Device_Is_Not_Ready 抛出异常 System.IO.FileNotFoundException,但异常 System.IO.IOException 是预期的。异常消息: System.IO.FileNotFoundException:设备未准备好。 (例外 来自 HRESULT:0x80070015)

这似乎是一个合理的设计决定,因为在这种特殊情况下,异常是从 HRESULT 返回代码生成的。这使得几乎不可能确定将引发哪个异常。至少在没有从我的测试应该...测试的单元中复制代码逻辑的情况下不会。

我的代码(我相信这可以抛出FileNotFoundDirectoryNotFound):

[TestMethod]
[ExpectedException(typeof(IOException))]
public void Call_Should_Throw_If_Device_Is_Not_Ready()
{
    foreach (DriveInfo drive in DriveInfo.GetDrives().Where(drive => !drive.IsReady))
    {
        DiskFreeSpace diskFreeSpace = DiskManagement.GetDiskFreeSpace(drive.RootDirectory.FullName);
        Assert.Fail("API call did not fail even though the drive reports that it is not ready.");
    }
    Assert.Inconclusive("All drives were ready. Try testing with an empty disc drive.");
}

我是否需要重新考虑编写单元测试的方式?

编辑

毕竟支持这种方案。真正需要的只是将AllowDerivedTypes 设置为true。

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

【问题讨论】:

  • 我不明白你想要达到什么目的。 ExpectedException 属性用于总是抛出预期异常的测试。这就是它正在测试的内容。你的测试总是会抛出一个IOException??如果设备准备好了,我猜没有。
  • 这就是它跳过准备好的驱动器的原因。如果所有驱动器都准备好,则断言是不确定的。如果方法调用没有抛出,则断言失败。
  • 在所有其他情况下,调用(应该)抛出一个扩展 IOException 的异常。但是很难确定是哪一个。

标签: c# mstest


【解决方案1】:

您可以创建自己的ExpectedException 属性,该属性将检查抛出的异常是否继承了该属性中定义的异常。

public sealed class MyExpectedException : ExpectedExceptionBaseAttribute
{
    private Type _expectedExceptionBaseType;

    public MyExpectedException(Type expectedExceptionType)
    {
        _expectedExceptionBaseType = expectedExceptionType;
    }

    protected override void Verify(Exception exception)
    {
        Assert.IsNotNull(exception);
        Assert.IsTrue(exception.GetType().IsInstanceOfType(typeof(_expectedExceptionBaseType)) || 
                      exception.GetType().IsSubclassOf(typeof(_expectedExceptionBaseType)));
    }
}

并将属性更改为您的测试:

[MyExpectedException(typeof(IOException))]

【讨论】:

  • 哇。就是这么简单。
  • 小问题:IsSubclassOf() 在预期的基本类型和实际类型相同时返回 false。
  • @StevenLiekens 已编辑。
  • 我刚刚注意到框架的属性带有一个AllowDerivedTypes 属性。我不知道我以前是怎么错过的。我在原始帖子中添加了一个示例。
猜你喜欢
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
  • 2014-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多