【问题标题】:TargetInvocationException in NSubstituteNSubstitute 中的 TargetInvocationException
【发布时间】:2013-10-22 01:53:59
【问题描述】:

我想写一个测试,检查我的抽象类构造函数是否正确处理了无效参数。我写了一个测试:

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void MyClassCtorTest()
{
    var dummy = Substitute.For<MyClass>("invalid-parameter");
}

这个测试没有通过,因为 NSubstitute 抛出了 TargetInvocationException 而不是 ArgumentException。我寻求的实际例外实际上是InnerException 中的TargetInvocationException。我可以编写一个辅助方法,例如:

internal static class Util {

    public static void UnpackException(Action a) {

        try {

            a();
        } catch (TargetInvocationException e) {

            throw e.InnerException;
        } catch (Exception) {

            throw new InvalidOperationException("Invalid exception was thrown!");
        }
    }
}

但我想,应该有某种通用的方法来解决这个问题。有吗?

【问题讨论】:

    标签: c# testing nsubstitute targetinvocationexception


    【解决方案1】:

    NSubstitute 目前没有解决这个问题的通用方法。

    其他一些解决方法包括手动对抽象类进行子类化以测试构造函数,或者手动断言内部异常而不是使用ExpectedException

    例如,假设我们有一个需要非负整数的抽象类:

    public abstract class MyClass {
        protected MyClass(int i) {
            if (i < 0) {
                throw new ArgumentOutOfRangeException("i", "Must be >= 0");
            }
        }
        // ... other members ...
    }
    

    我们可以在测试夹具中创建一个子类来测试基类构造函数:

    [TestFixture]
    public class SampleFixture {
        private class TestMyClass : MyClass {
            public TestMyClass(int i) : base(i) { }
            // ... stub/no-op implementations of any abstract members ...
        }
    
        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void TestInvalidConstructorArgUsingSubclass()
        {
            new TestMyClass(-5);
        }
        // Aside: I think `Assert.Throws` is preferred over `ExpectedException` now.
        // See http://stackoverflow.com/a/15043731/906
    }
    

    或者,您仍然可以使用模拟框架并断言内部异常。我认为这比上一个选项不太可取,因为我们不知道为什么要深入研究TargetInvocationException,但无论如何这里有一个例子:

        [Test]
        public void TestInvalidConstructorArg()
        {
            var ex = Assert.Throws<TargetInvocationException>(() => Substitute.For<MyClass>(-5));
    
            Assert.That(ex.InnerException, Is.TypeOf(typeof(ArgumentOutOfRangeException)));
        }
    

    【讨论】:

    • 你如何“...手动断言内部异常...”?
    • @hbob:我添加了两种方法的示例。如果您想了解更多信息,请告诉我。
    • 还有另一种方法。如果您有Dog : AAnimal 并想测试抽象AAnimal,您可以使用适当的测试创建抽象AAnimalTests。然后创建一个DogTests : AAnimalTests 类。当它的测试运行时,它们在一个具体的实现(Dog)上运行,所以你不需要一个假的。当有多个实现(CatHorseBird 等)时会变得有点混乱,因为每个实现都会运行“相同”的测试,但这也许不是一件坏事。我不知道这是否是“最佳实践”,但我已经做了一段时间了。你怎么看?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多