简体   繁体   中英

How to Put method using xUnit

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?

  1. I would suggest to collect the test cases:

    • Given an invalid book When I call put Then It returns bad request
    • Given a non-existing book When I call put Then It returns not Found
    • Given an existing book When I call put Then It returns ok
  2. I would suggest to AAA pattern for each test case, for example:

    • Arrange : Setup a book service mock which returns false whenever someone calls the update
    • Act : Call your controller's put method
    • Assert : Verify that the returned result is not found as expected
  3. 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); .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM