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

本文关键字:异常 构造函数 模拟 对象 断言 | 更新日期: 2023-09-27 17:50:03

假设: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:一个抽象类

因此,同意(alexander)这里可能不需要mock,也同意Stecy对.Throws NUnit Assert扩展的看法,您可以在测试中创建一个调用基类的类,如下所示:

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...

不需要在那里使用mock。实际上,mock在您的示例中没有做任何有趣的事情。

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

[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);
}

carol Tyl的回答可以通过使用Fluent断言来改进:

Func<MyFileType> createMyFileType = () => mock.Object;
createMyFileType.Should().Throw<TargetInvokationException>().WithInnerException<FileNotFoundException>();