【问题标题】:How to unit test catch block of this method?如何对这种方法的 catch 块进行单元测试?
【发布时间】:2013-01-17 13:53:37
【问题描述】:

我正在学习单元测试。如何使用 NUnit 和 Rhino Mock 对该方法进行单元测试?好吧,我已经测试了try 块并想测试catch 块的代码覆盖率。

[HttpPost]
public ActionResult AppraisalOrderIsAcceptedByEmployee(int appraisalOrderId)
{
    try
    {
        this.appraisalOrderService.SubmitAppraisalOrder(appraisalOrderId);
    }
    catch (MessageLoneException ex)
    {
        // Display validation errors
        PersistErrors(ex);

        // Remains on the same view
        return RedirectToAction("VerifyOrderDetails", new { id = appraisalOrderId });
    }
    return GetLoginRedirectCurrentUser();
}

【问题讨论】:

    标签: c# asp.net-mvc-3 error-handling nunit rhino-mocks


    【解决方案1】:

    假设appraisalOrderService 是一个接口(在适当架构的应用程序中是一个安全的假设),您的控制器将其作为构造函数注入,您可以使用您最喜欢的模拟框架轻松地模拟它。例如,使用 Rhino Mocks,您的测试可能如下所示:

    [TestMethod]
    public void AppraisalOrderIsAcceptedByEmployee_Should_Redirect_To_VerifyOrderDetails_Action_If_SubmitAppraisalOrder_Throws_A_MessageLoneException()
    {
        // arrange
        var appraisalOrderId = 5;
        var orderServiceMock = MockRepository.GenerateMock<IOrderService>();
        orderServiceMock
            .Expect(x => x.SubmitAppraisalOrder(appraisalOrderId))
            .Throw(new MessageLoneException());
        var sut = new MyController(orderServiceMock);
    
        // act
        var actual = sut.AppraisalOrderIsAcceptedByEmployee(appraisalOrderId);
    
        // assert
        Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
        Assert.AreEqual("VerifyOrderDetails", result.RouteValues["action"]);
        Assert.AreEqual(appraisalOrderId, result.RouteValues["id"]);
    }
    

    您还没有展示PersistErrors 方法是什么以及它的行为方式,因此很难说出测试它的正确方法。如果此方法正在使用它们,您可能需要模拟其他东西。鉴于您在上面的评论,我想您以某种方式使用AddModelErrorMethodModelState 添加错误。如果是这种情况,您可以在测试的断言阶段对其进行验证:

    Assert.IsFalse(sut.ModelState.IsValid);
    

    如果您知道存储错误的密钥:

    Assert.AreEqual(
        "some expected message",
        sut.ModelState["someKey"].Errors.Single().ErrorMessage
    );
    

    【讨论】:

    • 嘿,谢谢。我有一个问题。当我在另一个类中编写测试时,我应该使用反射来访问测试用例的私有方法吗?
    • 不,你应该使用任何反射。您应该对私有方法进行单元测试。那是实现细节。您应该测试调用这些私有方法的公共方法。
    【解决方案2】:

    您可能可以独立测试PersistErrors()

    RedirectToAction 是一个框架方法。无需测试框架。

    仅仅为了代码覆盖率而测试catch 块的内容似乎有点过头了。不涉及任何逻辑。

    您应该测试appraisalOrderService.SubmitApraisalOrder() 是否根据需要抛出MessageLoneException

    记住 80/20 规则。测试覆盖范围的框架效率不高,而且浪费了您作为开发人员恕我直言的宝贵时间。

    如果您仍想在此方法中测试 catch 块,您可以伪造您的服务,以便 FakeAppraisalOrderService.SubmitApraisalOrder() 抛出 MessageLoneException

    不过,我还是建议您将时间集中在测试实际逻辑上。 100% 的覆盖率是一个理想化的目标,而不是一个规则。

    【讨论】:

    • 虽然RedirectToAction 是一个框架方法,但它被传递的值应该被断言。
    • @TrevorPilley 你的断言到底是什么?那个appraisalOrderId 还是一样的吗?我没有看到任何代码在操纵它。
    • var result = (RedirectToRouteResult)controller.AppraisalOrderIsAcceptedByEmployee(appraisalOrderId); Assert.AreEqual(appraisalOrderId, result.RouteValues["id"]); Assert.AreEqual("VerifyOrderDetails", result.RouteValues["action"]); 您应该断言您正在重定向到正确的操作并将appearanceOrderId 作为路由值传回。
    • @TrevorPilley 这只是反映正在传递的参数。当然你可以测试它,但你为什么要测试呢?不涉及任何逻辑。没有决定每次都确保是正确的。我希望RedirectToAction() 方法能够正确地将参数转换为RouteValues。那是再次测试框架。但我知道这里的意见不同,我个人会专注于更相关的测试。
    • 您不是在测试框架的行为,而是在测试该方法调用重定向到具有正确值的正确操作。如果处理MessageLoneException,该方法的部分行为是它会重定向,因此您应该通过测试确认。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 2013-12-19
    • 1970-01-01
    • 2018-10-29
    • 2017-07-01
    • 2013-10-17
    • 1970-01-01
    相关资源
    最近更新 更多