如何在有 "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> 参数匹配器来接受传递给索引器的任何整数。