在 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 模型 StartDate
和 EndDate
设置为 DateTime.Now
,
您的测试应该在测试方法中使用 model.StartDate
和 model.EndDate
而不是 startDate
和 endDate
。因为它们的值会不同。
[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.EndDate
和 model.StartDate
的原因
如果您不关心开始日期值和结束日期值是否匹配,您可以...
A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, A<DateTime>._, A<DateTime>._))
.Returns(r);
我有这个方法需要测试
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 模型 StartDate
和 EndDate
设置为 DateTime.Now
,
您的测试应该在测试方法中使用 model.StartDate
和 model.EndDate
而不是 startDate
和 endDate
。因为它们的值会不同。
[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.EndDate
和 model.StartDate
如果您不关心开始日期值和结束日期值是否匹配,您可以...
A.CallTo(() => nprAppService.Completed<ExpandoObject>(nprUserId, A<DateTime>._, A<DateTime>._))
.Returns(r);