I try to test Update method using xUnit and I don't know how to do it, below is my code:
Put method in controller:
[HttpPut]
[Route("{id}")]
public IActionResult Put([FromBody]BookDto book, [FromRoute]int id)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
var isUpdated = _service.Update(book);
if (!isUpdated)
{
return NotFound();
}
return Ok();
}
BookService update method:
public bool Update(BookDto book)
{
var bookDb = _context.Books.FirstOrDefault(x => x.Id == book.Id);
if(bookDb == null)
{
return false;
}
bookDb.Title = book.Title;
_context.SaveChanges();
var existingAuthors = _context.Book_Authors.Where(x => x.BookId == book.Id).ToList();
_context.Book_Authors.RemoveRange(existingAuthors);
_context.SaveChanges();
foreach (var AuthorsId in book.AuthorsId)
{
var newBookAuthors = new Book_Author()
{
BookId = book.Id,
AuthorId = AuthorsId
};
_context.Book_Authors.Add(newBookAuthors);
}
_context.SaveChanges();
return true;
}
BookDto:
public class BookDto
{
public int Id { get; set; }
public string Title { get; set; }
public List<int> AuthorsId { get; set; }
}
Any suggestions how to write PutMethod test using Moq?
I would suggest to collect the test cases:
I would suggest to AAA pattern for each test case, for example:
Try to codify. For example
public void GivenANonExistingBook_WhenICallPut_ThenItReturnsNotFound()
{
//Arrange
var book = ...;
var serviceMock = new Mock<IBookService>();
serviceMock.Setup(svc => svc.Update(It.IsAny<BookDto>()))
.Returns(false);
var sut = new YourController(serviceMock.Object);
//Act
var result = sut.Put(book, 0);
//Assert
var actionResult = result as NotFoundResult;
Assert.IsNotNull(actionResult);
}
It is also a good practice to verify that the Update
method of the service has been called only once with the book
variable: serviceMock.Verify(svc => svc.Update(book), Times.Once);
.