繁体   English   中英

断言从模拟对象构造函数抛出的异常

[英]Asserting an exception thrown from a mock object constructor

假设:VS2010、.NET 4、C#、NUnit、Moq

我是 TDD 的新手,在完成项目时遇到了这个问题。

鉴于班级:

public abstract class MyFileType
{                
    public MyFileType(String fullPathToFile)
    {
        if (!File.Exists(fullPathToFile))
        {
            throw new FileNotFoundException();
        }

        // method continues

    }
}

我正在尝试使用以下方法对其进行测试:

[Test]
[ExpectedException(typeof(System.IO.FileNotFoundException))]
public void MyFileType_CreationWithNonexistingPath_ExceptionThrown()
{
    String nonexistingPath = "C:\\does\\not\\exist\\file.ext";
    var mock = new Mock<MyFileType>(nonexistingPath);
}

测试失败,NUnit 报告从未抛出异常。

我确实在 NUnit 文档中找到了一个部分,讨论了异常断言,但这些示例似乎不是我想要做的。 我仍在开始使用 NUnit 和 Moq,所以我可能会以错误的方式进行处理。

更新:

为了帮助澄清为什么这个例子使用抽象类,它是一系列文件类型的基类,其中只有数据的加载和处理在子类类型之间会有所不同。 我最初的想法是将 open/setup 的逻辑放到一个基类中,因为它对所有类型都是相同的。

在您引用 mock.Object 之前,不会调用构造函数。 这应该会触发您期望的异常。

附带说明一下,让构造函数抛出使用异常以外的异常通常是不好的做法(例如各种 ArgumentException 派生类)。大多数开发人员不希望 'new' 抛出异常,除非他们做错了什么。 文件不存在是一种异常,可以合法地发生在程序的控制之外,因此您可能希望将其设为静态工厂方法,而不是像“FromFileName”。 编辑:鉴于这是一个基类构造函数,这也不是真正适用的,因此您可能需要考虑在哪里进行此检查的最佳位置。 毕竟,该文件可能在任何时候都不存在,因此检查构造函数甚至可能没有意义(无论如何您都需要检查所有相关方法。)

我今天遇到了类似的问题。 我使用以下解决方案解决了这个问题:

[Test]
[ExpectedException(typeof(System.IO.FileNotFoundException))]
public void MyFileType_CreationWithNonexistingPath_ExceptionThrown()
{
    String nonexistingPath = "C:\\does\\not\\exist\\file.ext";
    var mock = new Mock<MyFileType>(nonexistingPath);
    try
    {
        var target = mock.Object;
    }
    catch(TargetInvocationException e)
    {
        if (e.InnerException != null)
        {
            throw e.InnerException;
        }
        throw;
    }
}

如果你必须让这个类成为一个抽象类,那么我们应该按照它的意图来实现它(简单性):MSDN:一个抽象类

因此,同意(与 alexanderb)此处可能不需要模拟,并且同意 .Thrrows NUnit Assert 扩展上的 Stecy,您可以在测试中创建一个调用基类的类,如下所示:

using System;
using System.IO;

namespace fileFotFoundException {
    public abstract class MyFile {

        protected MyFile(String fullPathToFile) {
            if (!File.Exists(fullPathToFile)) throw new FileNotFoundException();
        }
    }
}

namespace fileFotFoundExceptionTests {
    using fileFotFoundException;
    using NUnit.Framework;

    public class SubClass : MyFile {
        public SubClass(String fullPathToFile) : base(fullPathToFile) {
            // If we have to have it as an abstract class...
        }
    }

    [TestFixture]
    public class MyFileTests {

        [Test]
        public void MyFile_CreationWithNonexistingPath_ExceptionThrown() {
            const string nonExistingPath = "C:\\does\\not\\exist\\file.ext";

            Assert.Throws<FileNotFoundException>(() => new SubClass(nonExistingPath));
        }
    }
}

假设您使用的是最新版本的 NUnit(您应该使用),那么 ExpectedException 属性已被弃用。

您应该改为使用以下内容:

var exception = Assert.Throws<FileNotFoundException> (() => new MyFileType (nonExistingPath));
Assert.That (exception, Is.Not.Null);  // Or you can check for exception text...

无需在那里使用模拟。 事实上,模拟在你的例子中没有什么有趣的。

如果您尝试测试 MyFileType 类,如果文件不存在,它会抛出异常,为什么要创建模拟。 你的代码应该很简单

[Test]
[ExpectedException(typeof(System.IO.FileNotFoundException))]
public void MyFileType_CreationWithNonexistingPath_ExceptionThrown()
{
    // arrange
    var nonexistingPath = "C:\\does\\not\\exist\\file.ext";

    // act / assert
    var mock = new MyFileType(nonexistingPath);
}

Karol Tyl答案可以通过使用Fluent Assertions来改进:

Func<MyFileType> createMyFileType = () => mock.Object;

createMyFileType.Should().Throw<TargetInvokationException>().WithInnerException<FileNotFoundException>();

暂无
暂无

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

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