[ExpectedException(typeof(AnExceptionBaseException))]

Ste*_*ens 5 c# mstest

我以这样的方式编写了一个单元测试,它应该抛出AnExceptionor AnotherException,两者都派生于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.");
}
Run Code Online (Sandbox Code Playgroud)

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

编辑

毕竟支持这个场景。真正需要做的就是设置AllowDerivedTypes为 true。

[TestMethod]
[ExpectedException(typeof(IOException), AllowDerivedTypes = true)]
public void Call_Should_Throw_If_Device_Is_Not_Ready()
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

cha*_*sos 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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

[MyExpectedException(typeof(IOException))]
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚注意到框架的属性带有一个“AllowDerivedTypes”属性。我不知道我之前是怎么错过的。我在原来的帖子中添加了一个示例。 (2认同)