FakeItEasy 控制器测试 HttpGet 调用
FakeItEasy ControllerTest HttpGet Calls
我想开始使用 FakeItEasy 来测试查询。
我想编写的测试应该检查实体是否在 HttpGet 调用上 returned(获取所有并通过 Id 获取)
控制者:
public class ToDoController : ControllerBase
{
private readonly IMediator _mediator;
public ToDoController(IMediator mediator) =>
_mediator = mediator;
[HttpGet]
[Produces("application/json")]
[ProducesResponseType(typeof(IEnumerable<ToDoItem>), (int)HttpStatusCode.OK)]
public async Task<ActionResult<IEnumerable<ToDoItem>>> Get()
{
var result = await _mediator.Send(new ToDoItemsQuery(new
AllToDoItems())).ConfigureAwait(false);
if (result != null && result.Any())
{
return result.ToList();
}
throw new InvalidOperationException("TODO: error handling");
}
[HttpGet]
[Route("{id}")]
[Produces("application/json")]
[ProducesResponseType(typeof(ToDoItem), (int)HttpStatusCode.OK)]
public async Task<ActionResult<ToDoItem>> GetById(int itemId)
{
var result = await _mediator
.Send(new ToDoItemsQuery(new ToDoItemById(itemId)))
.ConfigureAwait(false);
if (result != null && result.Any())
{
return result.FirstOrDefault();
}
throw new InvalidOperationException("TODO: error handling");
}
}
}
测试类:
public class ToDoItemControllerTests : ControllerTestBase
{
private IMediator _mediator;
private ToDoController _sut;
public ToDoItemControllerTests()
{
_mediator = A.Fake<IMediator>();
_sut = new ToDoController(_mediator);
}
[TestMethod]
public async Task GetAllItemsAsync_SuccessTest()
{
A.CallTo(() => _mediator.Send(A<AllToDoItems>._,
A<CancellationToken>._)).Returns(A.CollectionOfFake<ToDoItem>(10));
var result = await _sut.Get();
Assert.IsNotNull(result);
A.CallTo(() => _mediator).MustHaveHappened();
}
[TestMethod]
public async Task GetItemByIdAsync_SuccessTest()
{
// Arrange
int itemId = 2;
var commandResult =
new List<ToDoItem>
{
new ToDoItem
{
Id = itemId
};
}
A.CallTo(() => MediatR.Send(A<ToDoItemById>._, A<CancellationToken>._)).Returns(commandResult);
// Act
var result = await _sut.GetById(itemId);
// Assert
Assert.IsNotNull(result);
A.CallTo(() => MediatR.Send(A<ToDoItemById>._, A<CancellationToken>._)).MustHaveHappened();
}
}
所以在第一个测试中,我将 A.CallTo 接口 IMediatR 设置为 return 10 ToDoItems。
在调试期间,我看到 _sut.Get() 进入控制器,输入正确的 method/api 调用。
控制器 return 中的 _mediator.Send() 是一个 Fake IEnumerable(不是我在测试方法的第一个 Call.To 中设置的 10 个项目,而是一个没有结果的枚举)。
由于 result.Any() 为假,控制器抛出 InvalidOperationException
我什至不能断言 result.IsNotNull()
我想测试的第二个测试是否在调用 API 时 return 编辑了 1 个项目。
我设置了 (a) 一个 int 类型的 itemId 作为参数,
(b) 带有 itemId 和设置中的 1 个 Item 的模拟(?)列表
(c) 对 mediatR 的调用应该 return 来自 (b)
的模拟列表
我从测试中调用,在调试中我看到调用 await _mediator.Sent() returning
ToDoItem 的 Fake Ienumerable,结果不为 null,但因为 result.Any() 为 false,
该项目没有得到 returned,我得到另一个 InvalidOperationException
我觉得我在测试设置中遗漏了一些东西..
一个假的数据库接口?
我不想让我的控制器冒险并减少 if 的限制,这样我的测试就会通过
编辑:
即使我将 if 条件更改为删除 Any 条件
我看到测试进入控制器,returning "First Or Default" 结果,
测试在 A Call To Must Have Happened 上失败。
预计会找到它一次或多次,但没有对假对象进行调用。
这个我真的不明白,我居然看到他在打电话?!
我浏览了 GitHub 以查找示例,但我找到的最接近的示例是带有方法的实体,这些方法是在接口中定义的。这里不是这样
看到官方文档并没有让我变得更聪明,所以我求助于 SO <3
提前致谢!
在第一个测试中,您使用 AllToDoItems
类型的参数配置对 Send
的调用。但是在控制器中,您实际上用 TodoItemsQuery
调用 Send
。因此调用不匹配,并且应用默认(未配置)行为,即 return 假 IEnumerable
。您需要像这样配置调用:
A.CallTo(() => _mediator.Send(A<TodoItemsQuery>._,
A<CancellationToken>._)).Returns(A.CollectionOfFake<ToDoItem>(10));
第二次测试,问题还是一样,用ToDoItemById
代替了AllToDoItems
我想开始使用 FakeItEasy 来测试查询。 我想编写的测试应该检查实体是否在 HttpGet 调用上 returned(获取所有并通过 Id 获取)
控制者:
public class ToDoController : ControllerBase
{
private readonly IMediator _mediator;
public ToDoController(IMediator mediator) =>
_mediator = mediator;
[HttpGet]
[Produces("application/json")]
[ProducesResponseType(typeof(IEnumerable<ToDoItem>), (int)HttpStatusCode.OK)]
public async Task<ActionResult<IEnumerable<ToDoItem>>> Get()
{
var result = await _mediator.Send(new ToDoItemsQuery(new
AllToDoItems())).ConfigureAwait(false);
if (result != null && result.Any())
{
return result.ToList();
}
throw new InvalidOperationException("TODO: error handling");
}
[HttpGet]
[Route("{id}")]
[Produces("application/json")]
[ProducesResponseType(typeof(ToDoItem), (int)HttpStatusCode.OK)]
public async Task<ActionResult<ToDoItem>> GetById(int itemId)
{
var result = await _mediator
.Send(new ToDoItemsQuery(new ToDoItemById(itemId)))
.ConfigureAwait(false);
if (result != null && result.Any())
{
return result.FirstOrDefault();
}
throw new InvalidOperationException("TODO: error handling");
}
}
}
测试类:
public class ToDoItemControllerTests : ControllerTestBase
{
private IMediator _mediator;
private ToDoController _sut;
public ToDoItemControllerTests()
{
_mediator = A.Fake<IMediator>();
_sut = new ToDoController(_mediator);
}
[TestMethod]
public async Task GetAllItemsAsync_SuccessTest()
{
A.CallTo(() => _mediator.Send(A<AllToDoItems>._,
A<CancellationToken>._)).Returns(A.CollectionOfFake<ToDoItem>(10));
var result = await _sut.Get();
Assert.IsNotNull(result);
A.CallTo(() => _mediator).MustHaveHappened();
}
[TestMethod]
public async Task GetItemByIdAsync_SuccessTest()
{
// Arrange
int itemId = 2;
var commandResult =
new List<ToDoItem>
{
new ToDoItem
{
Id = itemId
};
}
A.CallTo(() => MediatR.Send(A<ToDoItemById>._, A<CancellationToken>._)).Returns(commandResult);
// Act
var result = await _sut.GetById(itemId);
// Assert
Assert.IsNotNull(result);
A.CallTo(() => MediatR.Send(A<ToDoItemById>._, A<CancellationToken>._)).MustHaveHappened();
}
}
所以在第一个测试中,我将 A.CallTo 接口 IMediatR 设置为 return 10 ToDoItems。 在调试期间,我看到 _sut.Get() 进入控制器,输入正确的 method/api 调用。 控制器 return 中的 _mediator.Send() 是一个 Fake IEnumerable(不是我在测试方法的第一个 Call.To 中设置的 10 个项目,而是一个没有结果的枚举)。
由于 result.Any() 为假,控制器抛出 InvalidOperationException 我什至不能断言 result.IsNotNull()
我想测试的第二个测试是否在调用 API 时 return 编辑了 1 个项目。 我设置了 (a) 一个 int 类型的 itemId 作为参数, (b) 带有 itemId 和设置中的 1 个 Item 的模拟(?)列表 (c) 对 mediatR 的调用应该 return 来自 (b)
的模拟列表我从测试中调用,在调试中我看到调用 await _mediator.Sent() returning ToDoItem 的 Fake Ienumerable,结果不为 null,但因为 result.Any() 为 false, 该项目没有得到 returned,我得到另一个 InvalidOperationException
我觉得我在测试设置中遗漏了一些东西.. 一个假的数据库接口? 我不想让我的控制器冒险并减少 if 的限制,这样我的测试就会通过
编辑: 即使我将 if 条件更改为删除 Any 条件 我看到测试进入控制器,returning "First Or Default" 结果, 测试在 A Call To Must Have Happened 上失败。 预计会找到它一次或多次,但没有对假对象进行调用。 这个我真的不明白,我居然看到他在打电话?!
我浏览了 GitHub 以查找示例,但我找到的最接近的示例是带有方法的实体,这些方法是在接口中定义的。这里不是这样
看到官方文档并没有让我变得更聪明,所以我求助于 SO <3 提前致谢!
在第一个测试中,您使用 AllToDoItems
类型的参数配置对 Send
的调用。但是在控制器中,您实际上用 TodoItemsQuery
调用 Send
。因此调用不匹配,并且应用默认(未配置)行为,即 return 假 IEnumerable
。您需要像这样配置调用:
A.CallTo(() => _mediator.Send(A<TodoItemsQuery>._,
A<CancellationToken>._)).Returns(A.CollectionOfFake<ToDoItem>(10));
第二次测试,问题还是一样,用ToDoItemById
代替了AllToDoItems