在 C# 中伪造通用方法调用不会使用 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,endDate))
            .MustHaveHappened();
        result.Should().BeOfType<NotFoundobjectResult>()
            .Subject.Value.Should().BeOfType<string>();
    }

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

我该如何解决这个问题?

解决方法

假设 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.EndDate))
        .MustHaveHappened();
    result.Should().BeOfType<NotFoundObjectResult>()
        .Subject.Value.Should().BeOfType<string>();
}

更新:进一步说明

对于第一种通过传递伪对象进行配置的方法,返回类型应包括 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);