在 C# 中伪造泛型方法调用不会使用 FakeItEasy 返回正确的对象

Faking a generic method call in C# is not returning the correct object with FakeItEasy

我有这个方法需要测试

    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 通用方法 returns 一个对象而不是 OperationResult。

我该如何解决这个问题?

假设 CreateRandomDateRangeDto return 模型 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对象配置的方式,return类型应该包括Task.

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

第二种方法需要准确的 value/object 才能 return 指定的对象。这就是测试仅适用于 model.EndDatemodel.StartDate

的原因

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

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