Reputation: 6322
I am trying to test the web api method with xUnit and Moq but there comes a situation as it is using "this" keyword. Please see the code.
Web API Inteface
public interface IRepository
{
IEnumerable<Reservation> Reservations { get; }
Reservation this[int id] { get; }
}
There is this keyword Reservation this[int id] { get; }
The Web API Controller
[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);
}
}
The web api provides records from in-memory and not from database. There is a class Repository.cs
which contains records hard-coded.
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;
}
Now I want to mock for the web api method Get(int id)
but can't because of 'this' keyword. I tried below code but failed.
[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"
};
}
The mock code to look for is mockRepo.Setup(repo => repo.Reservations.this).Returns(Single());
. I get compile error. So please help me to fix it.
Upvotes: 1
Views: 93
Reputation: 247323
In order to recreate the desired behavior you can capture the passed argument in the Returns
and use it to create the fake model
[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"
};
Note the use of It.IsAny<int>
argument matcher to accept any integer passed into the indexer.
Upvotes: 2
Reputation: 1564
This might work for you:
mockRepo
.SetupSet(repo => repo[123456] = It.IsAny<int>())
.Callback((string name, object m) => {Single()});
Source: https://weblogs.asp.net/bleroy/mocking-indexer-setters-with-moq
Upvotes: 0