【问题标题】:Faking a generic method call in C# is not returning the correct object with FakeItEasy在 C# 中伪造泛型方法调用不会使用 FakeItEasy 返回正确的对象
【发布时间】:2021-02-19 06:13:00
【问题描述】:

我有这个方法需要测试

    public async Task<IActionResult> Completed(string nprUserId, [FromBody] DateRangeDto model)
    {
        var result = await _geAppService.Completed<ExpandoObject>(nprUserId, model.StartDate, model.EndDate);
        var r = result as OperationResult;

        if (r == null)
        {
            // There is no error.  Return JSON
            return Json(result, camelCaseOption);
        }
        else
        {
            // An error occurred.  Return a 404 and include the error message
            return NotFound(r.ErrorMessage);
        }
    }

这是我的测试

    [Fact]
    [Trait("Controller", "Completed")]
    public async Task Completed_WhenRIsNotNull_ReturnNotFoundWithMessage()
    {
        //arrange
        string nprUserId = string.Empty;
        var model = CreateRandomDateRangeDto();
        OperationResult r = CreateRandomOperationResult();
        var startDate = DateTime.Now;
        var endDate = DateTime.Now;

        //I tried this
        A.CallTo(nprAppService)
            .Where(call => call.Method.Name == "Completed")
            .WithReturnType<OperationResult>()
            .Returns(r);
       //I tried this as well
        A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, startDate, endDate))
            .Returns(r);

        //act
        var result = await controller.Completed(nprUserId, model);

        // Assert
        A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, startDate, endDate))
            .MustHaveHappened();
        result.Should().BeOfType<NotFoundObjectResult>()
            .Subject.Value.Should().BeOfType<string>();
    }

sut: 控制器被调用时,Complete 泛型方法返回一个对象而不是 OperationResult。

我该如何解决这个问题?

【问题讨论】:

  • 为什么你的方法不起作用:第一种方法:我们看不到nprAppService.Completed 的定义,但基于r = result as OperationResult,我猜它不会返回@ 987654325@。所以WithReturnType&lt;OperationResult&gt; 导致您的呼叫配置不匹配。我希望如果你把它切换到WithNonVoidReturnType,你会成功的。第二种方法:正如@Chekkan 所说,您将伪造配置为仅响应特定日期参数,因此当提供其他参数时,FakeItEasy 应用其默认行为。

标签: c# unit-testing fakeiteasy


【解决方案1】:

假设CreateRandomDateRangeDto 返回模型StartDateEndDate 设置为DateTime.Now

您的测试应该在测试方法中使用model.StartDatemodel.EndDate 而不是startDateendDate。因为他们的价值观会不同。

 [Fact]
 [Trait("Controller", "Completed")]
 public async Task Completed_WhenRIsNotNull_ReturnNotFoundWithMessage()
 {
     //arrange
     string nprUserId = string.Empty;
     var model = CreateRandomDateRangeDto();
     OperationResult r = CreateRandomOperationResult();

     A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, model.StartDate, model.EndDate))
        .Returns(r);

    //act
    var result = await controller.Completed(nprUserId, model);

    // Assert
    A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, model.StartDate, model.EndDate))
        .MustHaveHappened();
    result.Should().BeOfType<NotFoundObjectResult>()
        .Subject.Value.Should().BeOfType<string>();
}

更新:进一步说明

对于第一种通过fake对象进行配置的方法,返回类型应该包括Task

A.CallTo(nprAppService)
    .Where(call => call.Method.Name == "Completed")
    .WithReturnType<Task<OperationResult>>()
    .Returns(r)

第二种方法需要确切的值/对象才能返回指定的对象。这就是为什么该测试仅适用于 model.EndDatemodel.StartDate

如果您不关心开始和结束日期值是否匹配,您可以...

A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, A<DateTime>._, A<DateTime>._))
                .Returns(r);

【讨论】:

  • 为什么在这种情况下传递的值很重要?
  • 通过更新添加了更多解释,希望能让事情更清楚。
猜你喜欢
  • 1970-01-01
  • 2014-05-16
  • 1970-01-01
  • 1970-01-01
  • 2018-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多