如何在有 "this" 关键字时使用 xUnit 和 Moq 测试 web api 方法
How to test web api method with xUnit and Moq when there is "this" keyword
我正在尝试使用 xUnit 和 Moq 测试 Web api 方法,但出现了一种情况,因为它使用了“this”关键字。请看代码。
Web API 界面
public interface IRepository
{
IEnumerable<Reservation> Reservations { get; }
Reservation this[int id] { get; }
}
有这个关键字Reservation this[int id] { get; }
Web API 控制器
[ApiController]
[Route("api/[controller]")]
public class ReservationController : ControllerBase
{
private IRepository repository;
public ReservationController(IRepository repo) => repository = repo;
[HttpGet]
public IEnumerable<Reservation> Get() => repository.Reservations;
[HttpGet("{id}")]
public ActionResult<Reservation> Get(int id)
{
if (id == 0)
return BadRequest("Value must be passed in the request body.");
Reservation r = repository[id];
if (r is null)
return NotFound();
return Ok(r);
}
}
Web api 提供内存中而非数据库中的记录。有一个 class Repository.cs
包含硬编码的记录。
public class Repository : IRepository
{
private Dictionary<int, Reservation> items;
public Repository()
{
items = new Dictionary<int, Reservation>();
new List<Reservation> {
new Reservation {Id=1, Name = "Jack", StartLocation = "Edinberg", EndLocation="Yeti" },
new Reservation {Id=2, Name = "Nick", StartLocation = "Moscow", EndLocation="LKO" },
new Reservation {Id=3, Name = "Ramon", StartLocation = "London", EndLocation="Paris" }
}.ForEach(r => AddReservation(r));
}
public Reservation this[int id] => items.ContainsKey(id) ? items[id] : null;
public IEnumerable<Reservation> Reservations => items.Values;
}
现在我想模拟网络 api 方法 Get(int id)
但不能因为 'this' 关键字。我尝试了以下代码但失败了。
[Fact]
public void Test_GET_AReservations_BadRequest()
{
// Arrange
var mockRepo = new Mock<IRepository>();
mockRepo.Setup(repo => repo.Reservations.this).Returns(Single());
var controller = new ReservationController(mockRepo.Object);
// Act
var result = controller.Get();
// Assert
var model = Assert.IsAssignableFrom<IEnumerable<Reservation>>(result);
Assert.Equal(3, model.Count());
}
private static Reservation Single()
{
return new Reservation()
{
Id = 1,
Name = "Test One",
StartLocation = "SL1",
EndLocation = "EL1"
};
}
要查找的模拟代码是 mockRepo.Setup(repo => repo.Reservations.this).Returns(Single());
。我收到编译错误。所以请帮我修复一下。
这可能适合你:
mockRepo
.SetupSet(repo => repo[123456] = It.IsAny<int>())
.Callback((string name, object m) => {Single()});
来源:https://weblogs.asp.net/bleroy/mocking-indexer-setters-with-moq
为了重新创建所需的行为,您可以在 Returns
中捕获传递的参数并使用它来创建假模型
[Fact]
public void Should_GET_AReservation_By_Id() {
// Arrange
var mockRepo = new Mock<IRepository>();
mockRepo.Setup(repo => repo[It.IsAny<int>()])
.Returns((int id) => Single(id));
var controller = new ReservationController(mockRepo.Object);
int id = 123456
// Act
ActionResult<Reservation> result = controller.Get(id);
Reservation actual = result.Value;
// Assert
actual.Should().NotBeNull();
actual.Id.Should().Be(id);
}
private static Reservation Single(int id) =>
return new Reservation() {
Id = id,
Name = "Test One",
StartLocation = "SL1",
EndLocation = "EL1"
};
注意使用 It.IsAny<int>
参数匹配器来接受传递给索引器的任何整数。
我正在尝试使用 xUnit 和 Moq 测试 Web api 方法,但出现了一种情况,因为它使用了“this”关键字。请看代码。
Web API 界面
public interface IRepository
{
IEnumerable<Reservation> Reservations { get; }
Reservation this[int id] { get; }
}
有这个关键字Reservation this[int id] { get; }
Web API 控制器
[ApiController]
[Route("api/[controller]")]
public class ReservationController : ControllerBase
{
private IRepository repository;
public ReservationController(IRepository repo) => repository = repo;
[HttpGet]
public IEnumerable<Reservation> Get() => repository.Reservations;
[HttpGet("{id}")]
public ActionResult<Reservation> Get(int id)
{
if (id == 0)
return BadRequest("Value must be passed in the request body.");
Reservation r = repository[id];
if (r is null)
return NotFound();
return Ok(r);
}
}
Web api 提供内存中而非数据库中的记录。有一个 class Repository.cs
包含硬编码的记录。
public class Repository : IRepository
{
private Dictionary<int, Reservation> items;
public Repository()
{
items = new Dictionary<int, Reservation>();
new List<Reservation> {
new Reservation {Id=1, Name = "Jack", StartLocation = "Edinberg", EndLocation="Yeti" },
new Reservation {Id=2, Name = "Nick", StartLocation = "Moscow", EndLocation="LKO" },
new Reservation {Id=3, Name = "Ramon", StartLocation = "London", EndLocation="Paris" }
}.ForEach(r => AddReservation(r));
}
public Reservation this[int id] => items.ContainsKey(id) ? items[id] : null;
public IEnumerable<Reservation> Reservations => items.Values;
}
现在我想模拟网络 api 方法 Get(int id)
但不能因为 'this' 关键字。我尝试了以下代码但失败了。
[Fact]
public void Test_GET_AReservations_BadRequest()
{
// Arrange
var mockRepo = new Mock<IRepository>();
mockRepo.Setup(repo => repo.Reservations.this).Returns(Single());
var controller = new ReservationController(mockRepo.Object);
// Act
var result = controller.Get();
// Assert
var model = Assert.IsAssignableFrom<IEnumerable<Reservation>>(result);
Assert.Equal(3, model.Count());
}
private static Reservation Single()
{
return new Reservation()
{
Id = 1,
Name = "Test One",
StartLocation = "SL1",
EndLocation = "EL1"
};
}
要查找的模拟代码是 mockRepo.Setup(repo => repo.Reservations.this).Returns(Single());
。我收到编译错误。所以请帮我修复一下。
这可能适合你:
mockRepo
.SetupSet(repo => repo[123456] = It.IsAny<int>())
.Callback((string name, object m) => {Single()});
来源:https://weblogs.asp.net/bleroy/mocking-indexer-setters-with-moq
为了重新创建所需的行为,您可以在 Returns
中捕获传递的参数并使用它来创建假模型
[Fact]
public void Should_GET_AReservation_By_Id() {
// Arrange
var mockRepo = new Mock<IRepository>();
mockRepo.Setup(repo => repo[It.IsAny<int>()])
.Returns((int id) => Single(id));
var controller = new ReservationController(mockRepo.Object);
int id = 123456
// Act
ActionResult<Reservation> result = controller.Get(id);
Reservation actual = result.Value;
// Assert
actual.Should().NotBeNull();
actual.Id.Should().Be(id);
}
private static Reservation Single(int id) =>
return new Reservation() {
Id = id,
Name = "Test One",
StartLocation = "SL1",
EndLocation = "EL1"
};
注意使用 It.IsAny<int>
参数匹配器来接受传递给索引器的任何整数。