.NET November 9, 2020
15 min read

Creating an Application from Scratch using .NET Core and Angular — Part 7

In this article we are going to see how to create the unit tests for the Controllers in the API layer. To create these unit tests we are also going to use the xUnit and Moq framework.

Creating the Unit Test project for the API layer

Let’s start creating a new xUnit project for the API layer, similar to the one we created for the domain layer in the previous article (you can read the previous article clicking here). Open the solution with Visual Studio, and create a new xUnit project and add it on the “test” folder:

Select the xUnit, add the name of the unit test project and the location of the project (remember to add inside the ‘test’ folder):

It’s necessary to add the reference for the API layer in the unit test project. To do it, right-click on Dependencies (in the unit test project) > click in Add Reference and select the BookStore.API:

We also need to add the Moq framework in our project. To install MOQ open the Package Manager Console, select the BookStore.API.Tests project and execute this command (or install Moq through the NuGet Package Manager):

Install-Package Moq

Testing the BooksController

On this new unit test project, delete the class “UnitTest1” that is automatically created with the project, and create the class “BooksControllerTests”. On this class, we have three private properties that we are going to use in the unit test methods, and on the constructor, we initialize these properties. This is the initial structure of the BooksControllerTests class:

using AutoMapper;
using BookStore.API.Controllers;
using BookStore.Domain.Interfaces;
using Moq;

namespace BookStore.API.Tests
{
    public class BooksControllerTests
    {
        private readonly BooksController _booksController;
        private readonly Mock<IBookService> _bookServiceMock;
        private readonly Mock<IMapper> _mapperMock;

        public BooksControllerTests()
        {
            _bookServiceMock = new Mock<IBookService>();
            _mapperMock = new Mock<IMapper>();
            _booksController = new BooksController(_mapperMock.Object, _bookServiceMock.Object);
        }
    }
}

On line 16 and 17, we are creating a mock to use in the tests methods. This way we can simulate the return of the methods from the BookService class and also mock the result of the mapping, which is made by AutoMapper. On line 18 we are creating an instance of the BooksController.

This test class also has four private methods, two of them are responsible for creating the data that will be used in the tests, and the other two are responsible to do the mapping from the entity to the Dto. This way, instead of manually create the default data on the methods that we need to use this data, or always manually do the mapping, we can call these methods when necessary, avoiding repeating code and making the code cleaner and easier to use. For specific data then we can only manually create the objects that we need. These methods are:

  • CreateBook — which create a single Book
  • MapModelToBookResultDto — which do the mapping converting a Book entity to a BookResultDto
  • CreateBookList — which create a list of Book
  • MapModelToBookResultListDto— which do the mapping converting a List of Book entity to a List of BookResultDto

These are the methods:

private Book CreateBook()
{
    return new Book()
    {
        Id = 2,
        Name = "Book Test",
        Author = "Author Test",
        Description = "Description Test",
        Value = 10,
        CategoryId = 1,
        PublishDate = DateTime.MinValue.AddYears(40),
        Category = new Category()
        {
            Id = 1,
            Name = "Category Test"
        }
    };
}

private BookResultDto MapModelToBookResultDto(Book book)
{
    var bookDto = new BookResultDto()
    {
        Id = book.Id,
        Name = book.Name,
        Author = book.Author,
        Description = book.Description,
        PublishDate = book.PublishDate,
        Value = book.Value,
        CategoryId = book.CategoryId
    };
    return bookDto;
}

private List<Book> CreateBookList()
{
    return new List<Book>()
    {
        new Book()
        {
            Id = 1,
            Name = "Book Test 1",
            Author = "Author Test 1",
            Description = "Description Test 1",
            Value = 10,
            CategoryId = 1
        },
        new Book()
        {
            Id = 1,
            Name = "Book Test 2",
            Author = "Author Test 2",
            Description = "Description Test 2",
            Value = 20,
            CategoryId = 1
        },
        new Book()
        {
            Id = 1,
            Name = "Book Test 3",
            Author = "Author Test 3",
            Description = "Description Test 3",
            Value = 30,
            CategoryId = 2
        }
    };
}

private List<BookResultDto> MapModelToBookResultListDto(List<Book> books)
{
    var listBooks = new List<BookResultDto>();

    foreach (var item in books)
    {
        var book = new BookResultDto()
        {
            Id = item.Id,
            Name = item.Name,
            Author = item.Author,
            Description = item.Description,
            PublishDate = item.PublishDate,
            Value = item.Value,
            CategoryId = item.CategoryId
        };
        listBooks.Add(book);
    }
    return listBooks;
}

Now let’s implement the unit tests methods on the BooksControllerTests class.

The process to create the unit tests for the Controllers is similar to what was explained in the previous article. First, we need to check what the method is doing and create the unit test that will validate if the method is doing exactly what it should do. If we look at the BooksController we can see what we need to test, which are:

  • GetAll
  • GetById
  • GetBooksByCategory
  • Add
  • Update
  • Remove
  • Search
  • SearchBookWithCategory

Let’s start by looking at the first one, the GetAll:

[HttpGet]
public async Task<IActionResult> GetAll()
{
    var books = await _bookService.GetAll();

    return Ok(_mapper.Map<IEnumerable<BookResultDto>>(books));
}

For the GetAll we can test if:

  • The method returns Ok when a book exists
  • The method returns Ok when do not exist any book
  • The method calls the GetAll method from the Service class only one time

On line 4, where the GetAll method from the BookService class is called, we will mock, as we did with the repository classes when we were testing the Service classes. On line 6, in the return, you can see that there is a mapping from the result of the GetAll method, to a IEnumerable<BookResultDot>, so for this mapping, we also need to mock the result. This is the first unit test method:

[Fact]
public async void GetAll_ShouldReturnOk_WhenExistBooks()
{
    var books = CreateBookList();
    var dtoExpected = MapModelToBookResultListDto(books);

    _bookServiceMock.Setup(c => c.GetAll()).ReturnsAsync(books);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<List<Book>>())).Returns(dtoExpected);

    var result = await _booksController.GetAll();

    Assert.IsType<OkObjectResult>(result);
}

From line 4 to 8, we are doing the “Arrange” of this unit test.

On line 4 we calling the method to create a book list.

On line 5 we are calling the method to do the mapping from the List<Book> to List<BookResultDto>.

On line 7 we are mocking the return of the GetAll() method from the BookService class.

On line 8 we are mocking the mapping from List<Book> to IEnumerable<BookResultDto>.

On line 10 we are doing the “Act”, calling the method that we want to test.

And on line 12 we are doing the “Assert”, to check if the result is of type OkObjectResult, which is the expected type.

For the next unit test method, we will also have something similar:

[Fact]
public async void GetAll_ShouldReturnOk_WhenDoesNotExistAnyBook()
{
    var books = new List<Book>();
    var dtoExpected = MapModelToBookResultListDto(books);

    _bookServiceMock.Setup(c => c.GetAll()).ReturnsAsync(books);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<List<Book>>())).Returns(dtoExpected);

    var result = await _booksController.GetAll();

    Assert.IsType<OkObjectResult>(result);
}

The difference from this unit test method, to the previous one, is that in this method we are mocking the method to return an empty list of Book.

And the third test method for GetAll, we want to be sure that the GetAll method from the BookService class was called only once:

[Fact]
public async void GetAll_ShouldCallGetAllFromService_OnlyOnce()
{
    var books = CreateBookList();
    var dtoExpected = MapModelToBookResultListDto(books);

    _bookServiceMock.Setup(c => c.GetAll()).ReturnsAsync(books);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<List<Book>>())).Returns(dtoExpected);

    await _booksController.GetAll();

    _bookServiceMock.Verify(mock => mock.GetAll(), Times.Once);
}

For the next unit tests methods, we will have something similar. Let’s see the method GetById from the BooksController:

[HttpGet("{id:int}")]
public async Task<IActionResult> GetById(int id)
{
    var book = await _bookService.GetById(id);

    if (book == null) return NotFound();

    return Ok(_mapper.Map<BookResultDto>(book));
}

For the GetById method we can test if:

  • The method returns Ok when a book exists
  • The method returns NotFound when a book does not exist
  • The method calls the GetById method from the Service class only one time

These are the implementation of the test methods for the GetById method:

[Fact]
public async void GetById_ShouldReturnOk_WhenBookExist()
{
    var book = CreateBook();
    var dtoExpected = MapModelToBookResultDto(book);

    _bookServiceMock.Setup(c => c.GetById(2)).ReturnsAsync(book);
    _mapperMock.Setup(m => m.Map<BookResultDto>(It.IsAny<Book>())).Returns(dtoExpected);

    var result = await _booksController.GetById(2);

    Assert.IsType<OkObjectResult>(result);
}

[Fact]
public async void GetById_ShouldReturnNotFound_WhenBookDoesNotExist()
{
    _bookServiceMock.Setup(c => c.GetById(2)).ReturnsAsync((Book)null);

    var result = await _booksController.GetById(2);

    Assert.IsType<NotFoundResult>(result);
}

[Fact]
public async void GetById_ShouldCallGetByIdFromService_OnlyOnce()
{
    var book = CreateBook();
    var dtoExpected = MapModelToBookResultDto(book);

    _bookServiceMock.Setup(c => c.GetById(2)).ReturnsAsync(book);
    _mapperMock.Setup(m => m.Map<BookResultDto>(It.IsAny<Book>())).Returns(dtoExpected);

    await _booksController.GetById(2);

    _bookServiceMock.Verify(mock => mock.GetById(2), Times.Once);
}

Next is the GetBooksByCategory:

[HttpGet]
[Route("get-books-by-category/{categoryId:int}")]
public async Task<IActionResult> GetBooksByCategory(int categoryId)
{
    var books = await _bookService.GetBooksByCategory(categoryId);

    if (!books.Any()) return NotFound();

    return Ok(_mapper.Map<IEnumerable<BookResultDto>>(books));
}

For the GetBooksByCategory method we can test if:

  • The method returns Ok when book with searched category exists
  • The method returns NotFound when book with the searched category does not exist
  • The method calls the GetBooksByCategory method from the Service class only one time

These are the implementation of the test methods for the GetBooksByCategory method:

[Fact]
public async void GetBooksByCategory_ShouldReturnOk_WhenBookWithSearchedCategoryExist()
{
    var bookList = CreateBookList();
    var book = CreateBook();
    var dtoExpected = MapModelToBookResultListDto(bookList);

    _bookServiceMock.Setup(c => c.GetBooksByCategory(book.CategoryId)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<IEnumerable<Book>>())).Returns(dtoExpected);

    var result = await _booksController.GetBooksByCategory(book.CategoryId);

    Assert.IsType<OkObjectResult>(result);
}

[Fact]
public async void GetBooksByCategory_ShouldReturnNotFound_WhenBookWithSearchedCategoryDoesNotExist()
{
    var book = CreateBook();
    var dtoExpected = MapModelToBookResultDto(book);

    _bookServiceMock.Setup(c => c.GetBooksByCategory(book.CategoryId)).ReturnsAsync(new List<Book>());
    _mapperMock.Setup(m => m.Map<BookResultDto>(It.IsAny<Book>())).Returns(dtoExpected);

    var result = await _booksController.GetBooksByCategory(book.CategoryId);

    Assert.IsType<NotFoundResult>(result);
}

[Fact]
public async void GetBooksByCategory_ShouldCallGetBooksByCategoryFromService_OnlyOnce()
{
    var bookList = CreateBookList();
    var book = CreateBook();
    var dtoExpected = MapModelToBookResultListDto(bookList);

    _bookServiceMock.Setup(c => c.GetBooksByCategory(book.CategoryId)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<IEnumerable<Book>>())).Returns(dtoExpected);

    await _booksController.GetBooksByCategory(book.CategoryId);

    _bookServiceMock.Verify(mock => mock.GetBooksByCategory(book.CategoryId), Times.Once);
}

Next is the Add:

[HttpPost]
public async Task<IActionResult> Add(BookAddDto bookDto)
{
    if (!ModelState.IsValid) return BadRequest();

    var book = _mapper.Map<Book>(bookDto);
    var bookResult = await _bookService.Add(book);

    if (bookResult == null) return BadRequest();

    return Ok(_mapper.Map<BookResultDto>(bookResult));
}

For the Add method we can test if:

  • The method returns Ok when the book is added
  • The method returns BadRequest when the model state is invalid
  • The method returns BadRequest when the book is not added
  • The method calls the Add method from the Service class only one time

These are the implementation of the test methods for the Add method:

[Fact]
public async void Add_ShouldReturnOk_WhenBookIsAdded()
{
    var book = CreateBook();
    var bookAddDto = new BookAddDto() { Name = book.Name };
    var bookResultDto = MapModelToBookResultDto(book);

    _mapperMock.Setup(m => m.Map<Book>(It.IsAny<BookAddDto>())).Returns(book);
    _bookServiceMock.Setup(c => c.Add(book)).ReturnsAsync(book);
    _mapperMock.Setup(m => m.Map<BookResultDto>(It.IsAny<Book>())).Returns(bookResultDto);

    var result = await _booksController.Add(bookAddDto);

    Assert.IsType<OkObjectResult>(result);
}

[Fact]
public async void Add_ShouldReturnBadRequest_WhenModelStateIsInvalid()
{
    var bookAddDto = new BookAddDto();
    _booksController.ModelState.AddModelError("Name", "The field name is required");

    var result = await _booksController.Add(bookAddDto);

    Assert.IsType<BadRequestResult>(result);
}

[Fact]
public async void Add_ShouldReturnBadRequest_WhenBookResultIsNull()
{
    var book = CreateBook();
    var bookAddDto = new BookAddDto() { Name = book.Name };

    _mapperMock.Setup(m => m.Map<Book>(It.IsAny<BookAddDto>())).Returns(book);
    _bookServiceMock.Setup(c => c.Add(book)).ReturnsAsync((Book)null);

    var result = await _booksController.Add(bookAddDto);

    Assert.IsType<BadRequestResult>(result);
}

[Fact]
public async void Add_ShouldCallAddFromService_OnlyOnce()
{
    var book = CreateBook();
    var bookAddDto = new BookAddDto() { Name = book.Name };

    _mapperMock.Setup(m => m.Map<Book>(It.IsAny<BookAddDto>())).Returns(book);
    _bookServiceMock.Setup(c => c.Add(book)).ReturnsAsync(book);

    await _booksController.Add(bookAddDto);

    _bookServiceMock.Verify(mock => mock.Add(book), Times.Once);
}

Next is the Update:

HttpPut("{id:int}")]
public async Task<IActionResult> Update(int id, BookEditDto bookDto)
{
    if (id != bookDto.Id) return BadRequest();

    if (!ModelState.IsValid) return BadRequest();

    await _bookService.Update(_mapper.Map<Book>(bookDto));

    return Ok(bookDto);
}

On the Update method, there is an extra validation, which is the one on line 4. If the id is different than the id of the entity, should return BadRequest. So for the Update method, we can test if:

  • The method returns Ok when the book is updated correctly
  • The method returns BadRequest when the book id is different than the parameter id
  • The method returns BadRequest when the model state is invalid
  • The method calls the Update method from the Service class only one time

These are the implementation of the test methods for the Update method:

[Fact]
public async void Update_ShouldReturnOk_WhenBookIsUpdatedCorrectly()
{
    var book = CreateBook();
    var bookEditDto = new BookEditDto() { Id = book.Id,  Name = "Test" };

    _mapperMock.Setup(m => m.Map<Book>(It.IsAny<BookEditDto>())).Returns(book);
    _bookServiceMock.Setup(c => c.GetById(book.Id)).ReturnsAsync(book);
    _bookServiceMock.Setup(c => c.Update(book)).ReturnsAsync(book);

    var result = await _booksController.Update(bookEditDto.Id, bookEditDto);

    Assert.IsType<OkObjectResult>(result);
}

[Fact]
public async void Update_ShouldReturnBadRequest_WhenBookIdIsDifferentThenParameterId()
{
    var bookEditDto = new BookEditDto() { Id = 1,  Name = "Test" };

    var result = await _booksController.Update(2, bookEditDto);

    Assert.IsType<BadRequestResult>(result);
}

[Fact]
public async void Update_ShouldReturnBadRequest_WhenModelStateIsInvalid()
{
    var bookEditDto = new BookEditDto() { Id = 1 };
    _booksController.ModelState.AddModelError("Name", "The field name is required");

    var result = await _booksController.Update(1, bookEditDto);

    Assert.IsType<BadRequestResult>(result);
}

[Fact]
public async void Update_ShouldCallUpdateFromService_OnlyOnce()
{
    var book = CreateBook();
    var bookEditDto = new BookEditDto() { Id = book.Id, Name = "Test" };

    _mapperMock.Setup(m => m.Map<Book>(It.IsAny<BookEditDto>())).Returns(book);
    _bookServiceMock.Setup(c => c.GetById(book.Id)).ReturnsAsync(book);
    _bookServiceMock.Setup(c => c.Update(book)).ReturnsAsync(book);

    await _booksController.Update(bookEditDto.Id, bookEditDto);

    _bookServiceMock.Verify(mock => mock.Update(book), Times.Once);
}

Next is the Remove:

[HttpDelete("{id:int}")]
public async Task<IActionResult> Remove(int id)
{
    var book = await _bookService.GetById(id);
    if (book == null) return NotFound();

    await _bookService.Remove(book);

    return Ok();
}

For the Remove method we can test that:

  • The method returns Ok when the book is removed
  • The method returns NotFound when the book does not exist
  • The method calls the Remove method from the Service class only one time

These are the implementation of the test methods for the Remove method:

[Fact]
public async void Remove_ShouldReturnOk_WhenBookIsRemoved()
{
    var book = CreateBook();
    _bookServiceMock.Setup(c => c.GetById(book.Id)).ReturnsAsync(book);
    _bookServiceMock.Setup(c => c.Remove(book)).ReturnsAsync(true);

    var result = await _booksController.Remove(book.Id);

    Assert.IsType<OkResult>(result);
}

[Fact]
public async void Remove_ShouldReturnNotFound_WhenBookDoesNotExist()
{
    var book = CreateBook();
    _bookServiceMock.Setup(c => c.GetById(book.Id)).ReturnsAsync((Book)null);

    var result = await _booksController.Remove(book.Id);

    Assert.IsType<NotFoundResult>(result);
}

[Fact]
public async void Remove_ShouldCallRemoveFromService_OnlyOnce()
{
    var book = CreateBook();
    _bookServiceMock.Setup(c => c.GetById(book.Id)).ReturnsAsync(book);
    _bookServiceMock.Setup(c => c.Remove(book)).ReturnsAsync(true);

    await _booksController.Remove(book.Id);

    _bookServiceMock.Verify(mock => mock.Remove(book), Times.Once);
}

Next is the Search:

[Route("search/{bookName}")]
[HttpGet]
public async Task<ActionResult<List<Book>>> Search(string bookName)
{
    var books = _mapper.Map<List<Book>>(await _bookService.Search(bookName));

    if (books == null || books.Count == 0) return NotFound("None book was founded");

    return Ok(books);
}

For the Search method we can test if:

  • The method returns Ok when book with searched name exists
  • The method returns NotFound when book with searched name does not exist
  • The method calls the Search method from the Service class only one time

These are the implementation of the test methods for the Search method:

[Fact]
public async void Search_ShouldReturnOk_WhenBookWithSearchedNameExist()
{
    var bookList = CreateBookList();
    var book = CreateBook();

    _bookServiceMock.Setup(c => c.Search(book.Name)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<List<Book>>(It.IsAny<IEnumerable<Book>>())).Returns(bookList);

    var result = await _booksController.Search(book.Name);
    var actual = (OkObjectResult)result.Result;

    Assert.NotNull(actual);
    Assert.IsType<OkObjectResult>(actual);
}

[Fact]
public async void Search_ShouldReturnNotFound_WhenBookWithSearchedNameDoesNotExist()
{
    var book = CreateBook();
    var bookList = new List<Book>();

    var dtoExpected = MapModelToBookResultDto(book);
    book.Name = dtoExpected.Name;

    _bookServiceMock.Setup(c => c.Search(book.Name)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<Book>>(It.IsAny<Book>())).Returns(bookList);

    var result = await _booksController.Search(book.Name);
    var actual = (NotFoundObjectResult)result.Result;

    Assert.NotNull(actual);
    Assert.IsType<NotFoundObjectResult>(actual);
}

[Fact]
public async void Search_ShouldCallSearchFromService_OnlyOnce()
{
    var bookList = CreateBookList();
    var book = CreateBook();

    _bookServiceMock.Setup(c => c.Search(book.Name)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<List<Book>>(It.IsAny<IEnumerable<Book>>())).Returns(bookList);

    await _booksController.Search(book.Name);

    _bookServiceMock.Verify(mock => mock.Search(book.Name), Times.Once);
}

Next is the SearchBookWithCategory:

[Route("search-book-with-category/{searchedValue}")]
[HttpGet]
public async Task<ActionResult<List<Book>>> SearchBookWithCategory(string searchedValue)
{
    var books = _mapper.Map<List<Book>>(await _bookService.SearchBookWithCategory(searchedValue));

    if (!books.Any()) return NotFound("None book was founded");

    return Ok(_mapper.Map<IEnumerable<BookResultDto>>(books));
}

For the SearchBookWithCategory method we can test if:

  • The method returns Ok when book with the searched value exists
  • The method returns NotFound when book with the searched value does not exist
  • The method calls the SearchBookWithCategory method from the Service class only one time

These are the implementation of the test methods for the SearchBookWithCategory method:

[Fact]
public async void SearchBookWithCategory_ShouldReturnOk_WhenBookWithSearchedValueExist()
{
    var bookList = CreateBookList();
    var book = CreateBook();
    var bookResultList = MapModelToBookResultListDto(bookList);

    _bookServiceMock.Setup(c => c.SearchBookWithCategory(book.Name)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<Book>>(It.IsAny<List<Book>>())).Returns(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<List<Book>>())).Returns(bookResultList);

    var result = await _booksController.SearchBookWithCategory(book.Name);
    var actual = (OkObjectResult)result.Result;

    Assert.NotNull(actual);
    Assert.IsType<OkObjectResult>(actual);
}

[Fact]
public async void SearchBookWithCategory_ShouldReturnNotFound_WhenBookWithSearchedValueDoesNotExist()
{
    var book = CreateBook();
    var bookList = new List<Book>();

    _bookServiceMock.Setup(c => c.SearchBookWithCategory(book.Name)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<Book>>(It.IsAny<List<Book>>())).Returns(bookList);

    var result = await _booksController.SearchBookWithCategory(book.Name);
    var actual = (NotFoundObjectResult)result.Result;

    Assert.Equal("None book was founded", actual.Value);
    Assert.IsType<NotFoundObjectResult>(actual);
}

[Fact]
public async void SearchBookWithCategory_ShouldCallSearchBookWithCategoryFromService_OnlyOnce()
{
    var bookList = CreateBookList();
    var book = CreateBook();
    var bookResultList = MapModelToBookResultListDto(bookList);

    _bookServiceMock.Setup(c => c.SearchBookWithCategory(book.Name)).ReturnsAsync(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<Book>>(It.IsAny<List<Book>>())).Returns(bookList);
    _mapperMock.Setup(m => m.Map<IEnumerable<BookResultDto>>(It.IsAny<List<Book>>())).Returns(bookResultList);

    await _booksController.SearchBookWithCategory(book.Name);

    _bookServiceMock.Verify(mock => mock.SearchBookWithCategory(book.Name), Times.Once);
}

Executing the tests

To execute the test on Visual Studio, go to “Test” and click on “Test Explorer”:

On the test explorer, right click on the BookStore.API.Tests and click in “Run”, to execute all the tests from this project:

After the tests are executed, if everything works as expected, they will be green like in the image below:

The tests methods for the CategoriesController follows the same steps. Since the methods are not so different than the methods on the** BooksController**, I will not add them here on this article. You can check the complete code on my GitHub: https://github.com/henriquesd/BookStore

On the next article, we are going to see how we can create the unit tests for the Repository classes on the Infrastructure layer.

If you like this project, I kindly ask you to give a ⭐️ in the repository.

Thanks for reading!


References

XUnit

Moq