【问题标题】:moq unit testing in c# web apic# web api中的起订量单元测试
【发布时间】:2019-11-22 10:42:16
【问题描述】:

我正在尝试在 asp.net core 2 中测试一种 web api 方法。

网页接口

方法:

public IActionResult Delete(int id)
{
    try
    {
        var success = sportsService.DeleteSport(id);

        if (!success)
        {
            return new NotFoundResult();
        }
        return new OkResult();
    }
    catch (Exception e)
    {
        return new StatusCodeResult(400);
    }
}

单元测试部分:

private Mock<ISportsService> mockService;

[SetUp]
public void Setup()
{
    mockService.SetupSequence(x => x.DeleteSport(It.IsAny<int>())).
        Returns(true). // OkResult();
        Returns(false). // NotFoundResult()
        Throws(new Exception()); //Exception
}

测试方法如下所示。我对这种方法不清楚的是,测试该方法的正确方法是什么?

[Test]
public void TestStrategyControllerWithDelete()
{
    var result = controller.Delete(STRAT_ID);
    var okResult = result as ObjectResult;
    Assert.AreEqual(HttpStatusCode.NotFound, okResult.StatusCode);
    Assert.AreEqual(HttpStatusCode.OK, okResult.StatusCode);
    Assert.AreEqual(400, okResult.StatusCode);
}

并且我确定为 null ! 无法获取 okResult.StatusCode

【问题讨论】:

    标签: c# unit-testing moq


    【解决方案1】:

    您将模拟设置为:

    • 第一次调用时返回true
    • 第二次调用时返回false
    • 再次调用时抛出new Exception()

    但是,在您的测试中,您只调用一次(var result = controller.Delete(STRAT_ID);,因此您的 Moq 将始终返回 true

    编写 3 个单独的测试,而不是一个:

    [Test]
    public void Delete_ReturnsOkResult_IfDeleteSuccess()
    {
      const int deleteId = 1234;
      mockService.Setup(x => x.DeleteSport(deleteId)).Returns(true);
    
      var result = controller.Delete(deleteId);
    
      Assert.IsInstanceOf<OkResult>(result);
    }
    

    单元测试应该是独立的。它们应该能够以任何顺序运行而不会相互干扰。但是,通过在 [SetUp] 步骤中配置 SetupSequence(),您至少将其中 3 个绑定在一起并强制对它们下订单。

    编辑:“并且无法获取 okResult.StatusCode”* 更新为问题

    您正在返回 OKResultNotFoundResultStatusCodeResult。这些都不是从 ObjectResult 继承的,这就是它为 NULL 的原因。我已经更新了我的代码示例以检查显式类型 (OKResult),这需要针对每个测试用例进行更新。

    如果您想检查单个 StatusCodes,您可以将其大小写为 StatusCodeResult,因为所有返回类型都可以转换为此。

    【讨论】:

    • 好吧,那么我应该在 [SetUp] public void Setup() 中写什么?如果我们已经在做 mockService.Setup(x => x.DeleteSport(deleteId)).Returns(true);里面!!、[setup] 和 [Test]
    • 如果有人可以举例说明所有三种情况(好的、未找到、异常),那就太好了。谢谢
    • @Var 3 个案例将与显示的单个案例非常相似。您需要更改 mockService.Setup() 步骤和断言,因为它们是每个测试之间的变化。
    • 你能解释一下异常的“断言”吗? - Assert.IsInstanceOf(typeof(StatusCodeResult), result);?是正确的? - 我很想检查 400 状态返回与否
    • 为了返回 400/BadRequest,我认为以下方法应该有效:Assert.AreEqual(400, (result as StatusCodeResult).StatusCode);。或者,您可以返回 BadRequestResult 并测试 IsInstanceOf&lt;BadRequestResult&gt; 以使其与其他返回类型保持一致。
    【解决方案2】:

    你可以这样做,

    1) 成功:

    [Test]
    public void Delete_ReturnsOkResult_IfDeleteSuccess()
    {
      bool isSucceed = true;
      const int deleteId = 1234;
    
      this.MockSportService(isSucceed);
    
      var result = controller.Delete(deleteId);
    
      var okResult = result as ObjectResult;    
      Assert.AreEqual(HttpStatusCode.OK, okResult.StatusCode);
    }
    

    2) 失败:

    [Test]
    public void Delete_ReturnsNotFound_IfIdNotFound()
    {
      bool isSucceed = false;
      const int deleteId = 1234;
    
      this.MockSportService(isSucceed);
    
      var result = controller.Delete(deleteId);
    
    // Do proper asserts
    }
    

    3) 例外情况,

    [Test]
    public void Delete_ThrowsException_IfIdNotFound()
    {
      bool isSucceed = false;
      const int deleteId = 1234;
    
       mockService.Setup(x => x.DeleteSport(It.IsAny<int>())).
            Throws(new Exception());
    
      // Act
      var result = controller.Delete(deleteId);
    
      // Assert
      Assert.True(result is StatusCodeResult); // Asserting that the return type is StatusCodeResult
    
      // Casting the result as StatusCodeResult object
      var statusCodeResult = result as StatusCodeResult;
    
      // Asserting the status code
      Assert.AreEqual(400, statusCodeResult.StatusCode);
    }
    

    并且对于成功和失败都有嘲讽的常用方法,

    private void MockSportService(bool isSucceed)
    {
    mockService.Setup(x => x.DeleteSport(deleteId)).Returns(isSucceed);
    }
    

    【讨论】:

    • 谢谢,我的问题中的粗体字有什么线索吗?
    • 你能解释一下异常的“断言”吗?
    • @Var - 编辑了异常的断言。我希望这会有所帮助。
    【解决方案3】:

    您需要调用 controler.Delete(...) 方法 3 次以使最小起订量返回不同的状态/异常。

    我建议对每个返回的状态进行谨慎的测试 - 每个状态(真/假)一个,异常一个。

    【讨论】:

    • 见上面@Fermin 的回答——他成功了
    猜你喜欢
    • 1970-01-01
    • 2017-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    相关资源
    最近更新 更多