PersonsServiceTest.cs
using AutoFixture;
using Entities;
using FluentAssertions;
using Moq;
using RepositoryContracts;
using ServiceContracts.DTO;
using ServiceContracts.Enums;
using System.Linq.Expressions;
using Xunit.Abstractions;
using Serilog;
using Microsoft.Extensions.Logging;
using ServiceContracts;
using Services;
namespace CRUDxUnitTests
{
public class PersonsServiceTest
{
//private fields
private readonly Mock<IPersonsRepository> _personsRepositoryMock;
private readonly IPersonsRepository _personsRepository;
//private fields
private readonly IPersonsAdderService _personsAdderService;
private readonly IPersonsDeleterService _personsDeleterService;
private readonly IPersonsGetterService _personsGetterService;
private readonly IPersonsSorterService _personsSorterService;
private readonly IPersonsUpdaterService _personsUpdaterService;
private readonly ITestOutputHelper _testOutputHelper;
private readonly IFixture _fixture;
//constructor
public PersonsServiceTest(ITestOutputHelper testOutputHelper)
{
_fixture = new Fixture();
_testOutputHelper = testOutputHelper;
_personsRepositoryMock = new Mock<IPersonsRepository>();
_personsRepository = _personsRepositoryMock.Object;
var diagnosticContextMock = new Mock<IDiagnosticContext>();
var loggerAdderMock = new Mock<ILogger<PersonsAdderService>>();
var loggerDeleterMock = new Mock<ILogger<PersonsDeleterService>>();
var loggerGetterMock = new Mock<ILogger<PersonsGetterService>>();
var loggerSorterMock = new Mock<ILogger<PersonsSorterService>>();
var loggerUpdaterMock = new Mock<ILogger<PersonsUpdaterService>>();
_personsAdderService = new PersonsAdderService(_personsRepository, loggerAdderMock.Object, diagnosticContextMock.Object);
_personsDeleterService = new PersonsDeleterService(_personsRepository, loggerDeleterMock.Object, diagnosticContextMock.Object);
_personsGetterService = new PersonsGetterService(_personsRepository, loggerGetterMock.Object, diagnosticContextMock.Object);
_personsSorterService = new PersonsSorterService(_personsRepository, loggerSorterMock.Object, diagnosticContextMock.Object);
_personsUpdaterService = new PersonsUpdaterService(_personsRepository, loggerUpdaterMock.Object, diagnosticContextMock.Object);
}
#region AddPerson
//When we supply null value as PersonAddRequest, it should throw ArgumentNullException
[Fact]
public async Task AddPerson_NullPerson_ToBeArgumentNullExceltion()
{
//Arrange
PersonAddRequest? personAddRequest = null;
//Act
Func<Task> action = async () =>
{
await _personsAdderService.AddPerson(personAddRequest);
};
//Assert
await action.Should().ThrowAsync<ArgumentNullException>();
//await Assert.ThrowsAsync<ArgumentNullException>();
}
//When we supply null value as PersonName, it should throw ArgumentNullException
[Fact]
public async Task AddPerson_PersonNameIsNull_ToBeArgumentException()
{
//Arrange
PersonAddRequest? personAddRequest = _fixture.Build<PersonAddRequest>()
.With(p => p.PersonName, null as string).Create();
Person person = personAddRequest.ToPerson();
//When PersonsRepository.AddPerson is called, it has to return the same "person" object
_personsRepositoryMock.Setup(p => p.AddPersonAsync(It.IsAny<Person>()))
.ReturnsAsync(person);
//Act
Func<Task> action = async () =>
{
await _personsAdderService.AddPerson(personAddRequest);
};
//Assert
await action.Should().ThrowAsync<ArgumentException>();
}
//When we supply proper person details, it should insert the person into the persons list
//and it should return an object of PersonResponse, which includes with the newly generated person id
[Fact]
public async Task AddPerson_FullPersonDetails_ToBeSuccessful()
{
//Arrange
//PersonAddRequest? personAddRequest = _fixture.Create<PersonAddRequest>();
PersonAddRequest personAddRequest = _fixture.Build<PersonAddRequest>()
.With(p => p.Email, "person@example.com").Create();
Person person = personAddRequest.ToPerson();
PersonResponse person_response_expected = person.ToPersonResponse();
//If we supply any argument value to the AddPersonAsync method,
//it should return the same return value
_personsRepositoryMock.Setup(p => p.AddPersonAsync(It.IsAny<Person>()))
.ReturnsAsync(person);
//Act
PersonResponse personResponse = await _personsAdderService.AddPerson(personAddRequest);
person_response_expected.PersonId = personResponse.PersonId;
//Assert
personResponse.PersonId.Should().NotBe(Guid.Empty);
personResponse.Should().Be(person_response_expected);
}
#endregion
#region GetPersonByPersonId
//If we supply null as PersonId, it should return null as PersonResponse
[Fact]
public async Task GetPersonByPersonId_NullPersonId_ToBeNull()
{
//Arrange
Guid? personId = null;
//Act
PersonResponse? personResponse = await _personsGetterService.GetPersonByPersonId(personId);
//Assert
//Assert.Null(personResponse);
personResponse.Should().BeNull();
}
//If we supply a valid person id, it should return thr valid person details as PersonResponse object
[Fact]
public async Task GetPersonByPersonId_WithPersonId_ToBeSuccessful()
{
//Arrange
Person person = _fixture.Build<Person>()
.With(p => p.Email, "email@example.com")
.With(p => p.Country, null as Country)
.Create();
PersonResponse person_response_expected = person.ToPersonResponse();
_personsRepositoryMock.Setup(p => p.GetPersonByPersonIdAsync(It.IsAny<Guid>()))
.ReturnsAsync(person);
//Act
PersonResponse? personResponseGet = await _personsGetterService.GetPersonByPersonId(person.PersonId);
//Assert
//Assert.Equal(personResponseAdd, personResponseGet);
personResponseGet.Should().BeEquivalentTo(person_response_expected);
}
#endregion
#region GetAllPersons
//The GetAllPersons() should return an empty list by default
[Fact]
public async Task GetAllPersons_ToBeEmptyList()
{
//Arrange
List<Person> persons = new List<Person>();
_personsRepositoryMock.Setup(p => p.GetAllPersonsAsync())
.ReturnsAsync(persons);
//Act
List<PersonResponse> personResponses = await _personsGetterService.GetAllPersons();
//Assert
//Assert.Empty(personResponses);
personResponses.Should().BeEmpty();
}
//First, we will add few persons, and then when we call GetAllPersons(), it should return the sample persons that were added
[Fact]
public async Task GetPersons_WithFewPersons_ToBeSuccessful()
{
//Arrange
List<Person> persons = new List<Person>()
{
_fixture.Build<Person>()
.With(p => p.PersonName, "Smith")
.With(p => p.Email, "smith@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Marry")
.With(p => p.Email, "marry@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Rahman")
.With(p => p.Email, "rahman@example.com")
.With(p => p.Country, null as Country)
.Create()
};
List<PersonResponse> person_response_list_expected = persons.Select(p => p.ToPersonResponse()).ToList();
//print personResponsesAdd
_testOutputHelper.WriteLine("Expected:");
foreach (PersonResponse item in person_response_list_expected)
{
_testOutputHelper.WriteLine(item.ToString());
}
_personsRepositoryMock.Setup(p => p.GetAllPersonsAsync())
.ReturnsAsync(persons);
//Act
List<PersonResponse> personResponsesGet = await _personsGetterService.GetAllPersons();
//print personResponsesGet
_testOutputHelper.WriteLine("Actual:");
foreach (PersonResponse item in personResponsesGet)
{
_testOutputHelper.WriteLine(item.ToString());
}
//Assert
personResponsesGet.Should().BeEquivalentTo(person_response_list_expected);
}
#endregion
#region GetFilteredPersons
//If the search text is empty and search by is "PersonName", it should return all persons
[Fact]
public async Task GetFilteredPersons_EmptySearchText_ToBeSuccessful()
{
//Arrange
List<Person> persons = new List<Person>()
{
_fixture.Build<Person>()
.With(p => p.PersonName, "Smith")
.With(p => p.Email, "smith@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Marry")
.With(p => p.Email, "marry@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Rahman")
.With(p => p.Email, "rahman@example.com")
.With(p => p.Country, null as Country)
.Create()
};
List<PersonResponse> person_response_list_expected = persons.Select(p => p.ToPersonResponse()).ToList();
//print personResponsesAdd
_testOutputHelper.WriteLine("Expected:");
foreach (PersonResponse item in person_response_list_expected)
{
_testOutputHelper.WriteLine(item.ToString());
}
_personsRepositoryMock.Setup(p => p.GetFilteredPersonsAsync(It.IsAny<Expression<Func<Person, bool>>>()))
.ReturnsAsync(persons);
//Act
List<PersonResponse> personResponsesSearch =
await _personsGetterService.GetFilteredPersons(nameof(Person.PersonName), "");
//print personResponsesGet
_testOutputHelper.WriteLine("Actual:");
foreach (PersonResponse item in personResponsesSearch)
{
_testOutputHelper.WriteLine(item.ToString());
}
//Assert
personResponsesSearch.Should().BeEquivalentTo(person_response_list_expected);
}
//Search based on person name with some search string.
//It should return the matching persons
[Fact]
public async Task GetFilteredPersons_SearchByPersonName_ToBeSuccessful()
{
//Arrange
List<Person> persons = new List<Person>()
{
_fixture.Build<Person>()
.With(p => p.PersonName, "Smith")
.With(p => p.Email, "smith@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Marry")
.With(p => p.Email, "marry@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Rahman")
.With(p => p.Email, "rahman@example.com")
.With(p => p.Country, null as Country)
.Create()
};
List<PersonResponse> person_response_list_expected = persons.Select(p => p.ToPersonResponse()).ToList();
//print personResponsesAdd
_testOutputHelper.WriteLine("Expected:");
foreach (PersonResponse item in person_response_list_expected)
{
_testOutputHelper.WriteLine(item.ToString());
}
_personsRepositoryMock.Setup(p => p.GetFilteredPersonsAsync(It.IsAny<Expression<Func<Person, bool>>>()))
.ReturnsAsync(persons);
//Act
List<PersonResponse> personResponsesSearch =
await _personsGetterService.GetFilteredPersons(nameof(Person.PersonName), "ma");
//print personResponsesGet
_testOutputHelper.WriteLine("Actual:");
foreach (PersonResponse item in personResponsesSearch)
{
_testOutputHelper.WriteLine(item.ToString());
}
//Assert
personResponsesSearch.Should().BeEquivalentTo(person_response_list_expected);
}
#endregion
#region GetSortedPersons
//When we sort based on PersonName in DESC, it should return persons list in descending on PersonName
[Fact]
public async Task GetSortedPersons_ToBeSuccessful()
{
//Arrange
List<Person> persons = new List<Person>()
{
_fixture.Build<Person>()
.With(p => p.PersonName, "Smith")
.With(p => p.Email, "smith@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Marry")
.With(p => p.Email, "marry@example.com")
.With(p => p.Country, null as Country)
.Create(),
_fixture.Build<Person>()
.With(p => p.PersonName, "Rahman")
.With(p => p.Email, "rahman@example.com")
.With(p => p.Country, null as Country)
.Create()
};
List<PersonResponse> person_response_list_expected = persons.Select(p => p.ToPersonResponse())
.OrderByDescending(p => p.PersonName).ToList();
_personsRepositoryMock.Setup(p => p.GetAllPersonsAsync())
.ReturnsAsync(persons);
//print personResponsesAdd
_testOutputHelper.WriteLine("Expected:");
foreach (PersonResponse item in person_response_list_expected)
{
_testOutputHelper.WriteLine(item.ToString());
}
List<PersonResponse> allPersons = await _personsGetterService.GetAllPersons();
//Act
List<PersonResponse> persons_list_from_sort = await _personsSorterService
.GetSortedPersons(allPersons, nameof(Person.PersonName), SortOrderOptions.DESC);
//print personResponsesGet
_testOutputHelper.WriteLine("Actual:");
foreach (PersonResponse item in persons_list_from_sort)
{
_testOutputHelper.WriteLine(item.ToString());
}
//Assert
for (int i = 0; i < person_response_list_expected.Count; i++)
{
Assert.Equal(person_response_list_expected[i], persons_list_from_sort[i]);
}
persons_list_from_sort.Should().BeInDescendingOrder(p => p.PersonName);
}
#endregion
#region UpdatePerson
//When we supply null as PersonUpdateRequest, it should throw ArgumentNullException
[Fact]
public async Task UpdatePerson_NullPerson_ToBeArgumentNullException()
{
//Arrange
PersonUpdateRequest? personUpdateRequest = null;
//Act
Func<Task> action = async () =>
{
await _personsUpdaterService.UpdatePerson(personUpdateRequest);
};
//Assert
await action.Should().ThrowAsync<ArgumentNullException>();
}
//When we supply invalid person id, it should throw ArgumentNullException
[Fact]
public async Task UpdatePerson_InvalidPersonId_ToBeArgumentException()
{
//Arrange
PersonUpdateRequest? personUpdateRequest = _fixture.Build<PersonUpdateRequest>()
.Create();
//Act
Func<Task> action = async () =>
{
await _personsUpdaterService.UpdatePerson(personUpdateRequest);
};
//Assert
await action.Should().ThrowAsync<ArgumentException>();
}
//When PersonName is null, it should throw ArgumentException
[Fact]
public async Task UpdatePerson_PersonNameIsNull_ToBeArgumentException()
{
//Arrange
Person person = _fixture.Build<Person>()
.With(p => p.PersonName, null as string)
.With(p => p.Email, "John@example.com")
.With(p => p.Country, null as Country)
.With(p => p.Gender, GenderOptions.Male.ToString())
.Create();
PersonResponse person_response_from_add = person.ToPersonResponse();
PersonUpdateRequest personUpdateRequest = person_response_from_add.ToPersonUpdateRequest();
_personsRepositoryMock.Setup(p => p.UpdatePersonAsync(It.IsAny<Person>()))
.ReturnsAsync(person);
//Act
Func<Task> action = async () =>
{
await _personsUpdaterService.UpdatePerson(personUpdateRequest);
};
//Assert
await action.Should().ThrowAsync<ArgumentException>();
}
//Frist, add a new person and try to update the person name and email
[Fact]
public async Task UpdatePerson_PersonFullDetailsUpdation_ToBeSuccessful()
{
//Arrange
Person person = _fixture.Build<Person>()
.With(p => p.PersonName, "John")
.With(p => p.Email, "John@example.com")
.With(p => p.Country, null as Country)
.With(p => p.Gender, GenderOptions.Male.ToString())
.Create();
PersonResponse person_response_from_expected = person.ToPersonResponse();
PersonUpdateRequest person_update_request = person_response_from_expected.ToPersonUpdateRequest();
_personsRepositoryMock.Setup(p => p.UpdatePersonAsync(It.IsAny<Person>()))
.ReturnsAsync(person);
_personsRepositoryMock.Setup(p => p.GetPersonByPersonIdAsync(It.IsAny<Guid>()))
.ReturnsAsync(person);
//Act
PersonResponse personResponseUpdate = await _personsUpdaterService.UpdatePerson(person_update_request);
//Assert
personResponseUpdate.Should().BeEquivalentTo(person_response_from_expected);
}
#endregion
#region DeletePerson
//If you supply an valid PersonId, it should return true
[Fact]
public async Task DeletePerson_ValidPersonId_ToBeTrue()
{
//Arrange
Person person = _fixture.Build<Person>()
.With(p => p.PersonName, "John")
.With(p => p.Email, "John@example.com")
.With(p => p.Country, null as Country)
.With(p => p.Gender, GenderOptions.Male.ToString())
.Create();
PersonResponse personResponse = person.ToPersonResponse();
_personsRepositoryMock.Setup(p => p.DeletePersonByPersonIdAsync(It.IsAny<Guid>()))
.ReturnsAsync(true);
_personsRepositoryMock.Setup(p => p.GetPersonByPersonIdAsync(It.IsAny<Guid>()))
.ReturnsAsync(person);
//Act
bool isDeleted = await _personsDeleterService.DeletePerson(personResponse.PersonId);
//Assert
isDeleted.Should().BeTrue();
}
//If you supply an Invalid PersonId, it should return false
[Fact]
public async Task DeletePerson_InvalidPersonId_ToBeFalse()
{
//Act
bool isDeleted = await _personsDeleterService.DeletePerson(Guid.NewGuid());
//Assert
isDeleted.Should().BeFalse();
}
#endregion
}
}
PersonsControllerTest.cs
using AutoFixture;
using Moq;
using ServiceContracts;
using FluentAssertions;
using CRUDExample.Controllers;
using ServiceContracts.DTO;
using ServiceContracts.Enums;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace CRUDxUnitTests
{
public class PersonsControllerTest
{
private readonly IFixture _fixture;
private readonly Mock<ICountriesService> _countriesServiceMock;
private readonly Mock<IPersonsAdderService> _personsAdderServiceMock;
private readonly Mock<IPersonsDeleterService>
_personsDeleterServiceMock;
private readonly Mock<IPersonsGetterService> _personsGetterServiceMock;
private readonly Mock<IPersonsSorterService> _personsSorterServiceMock;
private readonly Mock<IPersonsUpdaterService>
_personsUpdaterServiceMock;
private readonly Mock<ILogger<PersonsController>> _loggerMock;
private readonly ICountriesService _countriesService;
//private fields
private readonly IPersonsAdderService _personsAdderService;
private readonly IPersonsDeleterService _personsDeleterService;
private readonly IPersonsGetterService _personsGetterService;
private readonly IPersonsSorterService _personsSorterService;
private readonly IPersonsUpdaterService _personsUpdaterService;
private readonly ILogger<PersonsController> _logger;
public PersonsControllerTest()
{
_fixture = new Fixture();
_countriesServiceMock = new Mock<ICountriesService>();
_personsAdderServiceMock = new Mock<IPersonsAdderService>();
_personsDeleterServiceMock = new Mock<IPersonsDeleterService>();
_personsGetterServiceMock = new Mock<IPersonsGetterService>();
_personsSorterServiceMock = new Mock<IPersonsSorterService>();
_personsUpdaterServiceMock = new Mock<IPersonsUpdaterService>();
_loggerMock = new Mock<ILogger<PersonsController>>();
_countriesService = _countriesServiceMock.Object;
_personsAdderService = _personsAdderServiceMock.Object;
_personsDeleterService = _personsDeleterServiceMock.Object;
_personsGetterService = _personsGetterServiceMock.Object;
_personsSorterService = _personsSorterServiceMock.Object;
_personsUpdaterService = _personsUpdaterServiceMock.Object;
_logger = _loggerMock.Object;
}
//Test Cases
#region Index
[Fact]
public async Task Index_ShouldReturnIndexViewWithPersonsList()
{
//Arrange
List<PersonResponse> persons_response_list =
_fixture.Create<List<PersonResponse>>();
_personsGetterServiceMock.Setup(p =>
p.GetFilteredPersons(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(persons_response_list);
_personsSorterServiceMock.Setup(p =>
p.GetSortedPersons(It.IsAny<List<PersonResponse>>(), It.IsAny<string>(),
It.IsAny<SortOrderOptions>())).ReturnsAsync(persons_response_list);
PersonsController personsController = new
PersonsController(_personsAdderService,_personsDeleterService,_personsGetterService,_personsSorterService,_personsUpdaterService, _countriesService, _logger);
//Act
IActionResult result = await
personsController.Index(_fixture.Create<string>(), _fixture.Create<string>(),
_fixture.Create<string>(), _fixture.Create<SortOrderOptions>());
//Assert
ViewResult viewResult = Assert.IsType<ViewResult>(result);
viewResult.ViewData.Model.Should().BeAssignableTo<IEnumerable<PersonResponse>>();
viewResult.ViewData.Model.Should().Be(persons_response_list);
}
#endregion
#region Create
[Fact]
public async Task Create_IfModelErrors_ToReturnCreateView()
{
//Arrange
PersonAddRequest personAddRequest =
_fixture.Create<PersonAddRequest>();
PersonResponse personResponse = _fixture.Create<PersonResponse>();
List<CountryResponse> countries =
_fixture.Create<List<CountryResponse>>();
_countriesServiceMock.Setup(c => c.GetAllCountries())
.ReturnsAsync(countries);
_personsAdderServiceMock.Setup(p =>
p.AddPerson(It.IsAny<PersonAddRequest>()))
.ReturnsAsync(personResponse);
PersonsController personsController = new
PersonsController(_personsAdderService, _personsDeleterService,
_personsGetterService, _personsSorterService, _personsUpdaterService,
_countriesService, _logger);
//Act
personsController.ModelState.AddModelError("PersonName", "Person Name
can't be blank");
IActionResult result = await
personsController.Create(personAddRequest);
//Assert
ViewResult viewResult = Assert.IsType<ViewResult>(result);
viewResult.ViewData.Model.Should().BeAssignableTo<PersonAddRequest>();
viewResult.ViewData.Model.Should().Be(personAddRequest);
}
[Fact]
public async Task Create_IfNoModelErrors_ToReturnRedirectToIndex()
{
//Arrange
PersonAddRequest personAddRequest =
_fixture.Create<PersonAddRequest>();
PersonResponse personResponse = _fixture.Create<PersonResponse>();
List<CountryResponse> countries =
_fixture.Create<List<CountryResponse>>();
_countriesServiceMock.Setup(c => c.GetAllCountries())
.ReturnsAsync(countries);
_personsAdderServiceMock.Setup(p =>
p.AddPerson(It.IsAny<PersonAddRequest>()))
.ReturnsAsync(personResponse);
PersonsController personsController = new
PersonsController(_personsAdderService, _personsDeleterService,
_personsGetterService, _personsSorterService, _personsUpdaterService,
_countriesService, _logger);
//Act
IActionResult result = await
personsController.Create(personAddRequest);
//Assert
RedirectToActionResult redirectToActionResult =
Assert.IsType<RedirectToActionResult>(result);
redirectToActionResult.ControllerName.Should().Be("Persons");
redirectToActionResult.ActionName.Should().Be("Index");
}
#endregion
}
}
Gitee获取源码: