如何测试方法是否在特定输入上抛出异常

How to test that a method throws an exception on specific input

在下面的方法中,当 model.test 为空时,我希望此方法抛出异常。

public bool Create(Test model)
{
    if (model.test == null)
    {
        throw new InvalidOperationException("nanana.");

    }
    try
    {
        return true;
    }
    catch (InvalidOperationException ex) { throw; }
}

这是我当前的测试:

[Test]
public void Only_one_property_should_be_set()
{
    var rep  =  Substitute.For<ITestRepository>();

    var x = rep.Create(model.ToEntity());

    Assert.Throws<InvalidOperationException>(() => rep.Create(model.ToEntity()));
}

它不起作用,因为 x returns 始终为 false。

我可以直接替换 TestRepository,但随后我会将项目插入数据库,但我不想这样做。如何在不将项目插入数据库的情况下使用 NUnit 和 NSubstitute 测试存储库异常?

您的操作存在几个问题。正如评论中已经说过的那样,模拟/替换您要测试的 class 通常不是一个好主意。 Mocks 和 Substitutes 用于允许您通过被测代码控制逻辑流,而不是替换被测代码。

由于您显示的代码除了模型 class 之外没有任何依赖项,因此在这种情况下您根本没有理由使用替代品。如果您的代码看起来像这样(伪代码),您将使用 Substitute

if(model.Test == null) {
   throw someException
}
_someDependency->Create(model.Value1, model.Value2, model.Test)

在上面的代码中,_someDependency 是一些基础数据库交互 class,已通过其构造函数注入到存储库中。然后,您可以为 _someDependency 创建一个替代品,以影响 Create 方法的流程,或验证与依赖项的交互。

就目前的方法测试而言,没有理由不能只传入具有 test==null 的模型。该方法中的逻辑流程是这样的,如果该测试失败,您不会期望将数据写入数据库,这就是检查的重点。所以,你的测试可以简单地看起来像这样:

[Test]
public void CreateShouldThrowIfModelTestIsNull()
{
    var testModel = model.ToEntity();

    var sut  =  new TestRepository();

    testModel.test = null;

    try {
        sutCreate(testModel);
        Assert.Fail("Expected Exception");
    } catch(InvalidOperationException ex) {
        Assert.AreEqual("nanana.", ex.Message);
    }
}