Why my mock object not working truly in xUnit test project? - c#

I have a Category table in my project, I used Generic repository and Unit of Work pattern in my project. It is an API. It is working when I use mock of UnitOfWork lonely but It is not working when I want to check my controller result. My controller response is 404 always. I think it is because of my mistake in setup but I don't know where it is.
`
[DisplayName("Category Table")]
public class Category
{
public int Id { get; set; }
public int? Priority { get; set; }
public string Name { get; set; }
public string? Details { get; set; }
public bool Enabled { get; set; }
public int? ParentCategoryId { get; set; }
public virtual Category Parent { get; set; }
public virtual IList<Category> Children { get; set; }
}
public interface IGenericRepository<T> where T : class, new()
{
Task<T> GetByIdAsync(object id);
Task<IReadOnlyList<T>> ListAllAsync();
Task<T> GetEntityWithSpec(ISpecification<T> spec);
Task<IReadOnlyList<T>> ListWithSpecAsync(ISpecification<T> spec);
...
}
public class GenericRepository<T> : IGenericRepository<T> where T : class, new()
{
private readonly FactoryContext _context;
public GenericRepository(FactoryContext context)
{
_context = context;
}
public async Task<T> GetByIdAsync(object id)
{
return await _context.Set<T>().FindAsync(id);
}
public async Task<IReadOnlyList<T>> ListAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public async Task<T> GetEntityWithSpec(ISpecification<T> spec)
{
return await ApplySpecification(spec).FirstOrDefaultAsync();
}
public async Task<IReadOnlyList<T>> ListWithSpecAsync(ISpecification<T> spec)
{
return await ApplySpecification(spec).ToListAsync();
}
...
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(), spec);
}
}
public interface IUnitOfWork : IDisposable
{
IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class, new();
Task<int> Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly FactoryContext _context;
private Hashtable _repositories;
public UnitOfWork(FactoryContext context)
{
_context = context;
}
public async Task<int> Complete()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
public IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class, new()
{
if (_repositories == null) _repositories = new Hashtable();
var type = typeof(TEntity).Name;
if (!_repositories.ContainsKey(type))
{
var repositoryType = typeof(GenericRepository<>);
var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _context);
_repositories.Add(type, repositoryInstance);
}
return (IGenericRepository<TEntity>)_repositories[type];
}
}
public class CategoriesController : BaseApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public CategoriesController(IUnitOfWork unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
[HttpGet("getcategorybyid/{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<CategoryToReturnDto>> GetCategoryById(int id)
{
try
{
var spec = new GetCategoriesWithParentsSpecification(id);
var category = await _unitOfWork.Repository<Category>().GetEntityWithSpec(spec);
if (category.Id == 0) return NotFound(new ApiResponse(404));
var returnCategories = _mapper.Map<Category, CategoryToReturnDto>(category);
return new OkObjectResult(new ApiResponse(200, "Ok", returnCategories));
}
catch (Exception ex)
{
return BadRequest(new ApiResponse(400, ex.Message));
}
}
}
public class CategoriesControllerTests
{
private readonly Mock<IMapper> _mapper;
private readonly Mock<IUnitOfWork> _unitOfWork;
public CategoriesControllerTests()
{
_mapper = new Mock<IMapper>();
_unitOfWork = new Mock<IUnitOfWork>();
}
[Fact]
public async Task Get_OK_ObjectResult_CategoryById()
{
//Arrange
Category newCategory = CreateTestCategory();
var spec = new GetCategoriesWithParentsSpecification(1);
_unitOfWork.Setup(x => x.Repository<Category>().GetEntityWithSpec(spec)).ReturnsAsync(newCategory)
.Verifiable();
//Act
// Here it is working and result2 has data.
var result2 = await _unitOfWork.Object.Repository<Category>().GetEntityWithSpec(spec);
var controller = new CategoriesController(_unitOfWork.Object, _mapper.Object);
var result = await controller.GetCategoryById(1);
// Assert
result.Value?.Id.ShouldBe(newCategory.Id);
result.Value?.Name.ShouldBeEquivalentTo(newCategory.Name);
result.Value?.Name.ShouldBeEquivalentTo("newCategory.Name");
// My problem here. My result is NotFoundObjectResult always.
result.Result.ShouldBeOfType<OkObjectResult>();
}
private Category CreateTestCategory()
{
return new Category()
{
Id = 1,
Priority = 1,
Name = "Test Category",
Enabled = true,
Details = "Testing category data"
};
}
}
`

The spec that you pass during the moq setup isn't the same as the spec that your repository receives inside the controller
In your test, you should change the setup in such a way that it checks the type of input instead and avoid passing a reference.
_unitOfWork.Setup(x => x.Repository<Category>()
.GetEntityWithSpec(It.IsAny<ISpecification<Category>>()))
.ReturnsAsync(newCategory)
.Verifiable();
Here we set up the moq in a way that as long as the input is ISpecification<Category>, it returns newCategory

The specificatio didn't use truly. Your setup should be like this:
_unitOfWork.Setup(x => x.Repository<Category>()
.GetEntityWithSpec(It.IsAny<ISpecification<Category>>()))
.ReturnsAsync(newCategory)
.Verifiable();

Related

ASP.NET Core Web API retrieves blank record in API GET Request

I am using ASP.NET Core Web API. I have these models:
public abstract class EntityBase
{
[Key]
public int Id { get; set; }
}
public class Mandate : EntityBase
{
public int? MerchantId { get; set; }
public DateTime DueDate { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
[ForeignKey("MerchantId")]
public virtual Merchant Merchant { get; set; }
}
Model: Mandate
ViewModel (Dto):
public class MandateGetDto
{
public int? MerchantId { get; set; }
public DateTime DueDate { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
IBaseRepository:
public interface IBaseRepository<T> where T : BaseEntity
{
Task<IEnumerable<T>> GetAll();
bool EntityExists(long id);
}
BaseRepository:
public class BaseRepository<T> : IBaseRepository<T> where T : AuditableBaseEntity
{
private readonly DDMDbContext _context;
private DbSet<T> _entities;
public BaseRepository(DDMDbContext context)
{
_context = context;
_entities = context.Set<T>();
}
public async Task<IEnumerable<T>> GetAll()
{
var list = await _entities.ToListAsync();
return list;
}
public bool EntityExists(long id)
{
return _entities.Any(x => x.Id == id);
}
}
EntityMapper:
public MandateGetDto FromMandateToMandateGetDto(Mandate mandate)
{
MandateGetDto mandateDto = new MandateGetDto();
mandateDto.MerchantId = mandate.MerchantId;
mandateDto.DueDate = mandate.DueDate;
mandateDto.StartDate = mandate.StartDate;
mandateDto.EndDate = mandate.EndDate;
return mandateDto;
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private readonly DContext _context;
public UnitOfWork(DContext context)
{
_context = context;
}
#region Mandate
private readonly IBaseRepository<Mandate> _mandateRepository;
public IBaseRepository<Mandate> MandateRepository => _mandateRepository ?? new BaseRepository<Mandate>(_context);
# endregion
public void Dispose()
{
if (_context != null)
{
_context.Dispose();
}
}
}
Below is the code I have written for the Mandate service which retrieves all the records for the mandates.
MandateService:
public async Task<ResponsePagination<GenericPagination<MandateGetDto>>> GetAll(int page, int sizeByPage)
{
string nextRoute = null, previousRoute = null;
IEnumerable<Mandate> data = await _unitOfWork.MandateRepository.GetAll();
var mapper = new EntityMapper();
var mandatesDto = data.Select(m => mapper.FromMandateToMandateGetDto(m)).ToList();
GenericPagination<MandateGetDto> objGenericPagination = GenericPagination<MandateGetDto>.Create(mandatesDto, page, sizeByPage);
ResponsePagination<GenericPagination<MandateGetDto>> response = new ResponsePagination<GenericPagination<MandateGetDto>>(objGenericPagination);
response.CurrentPage = objGenericPagination.CurrentPage;
response.HasNextPage = objGenericPagination.HasNextPage;
response.HasPreviousPage = objGenericPagination.HasPreviousPage;
response.PageSize = objGenericPagination.PageSize;
response.TotalPages = objGenericPagination.TotalPages;
response.TotalRecords = objGenericPagination.TotalRecords;
response.Data = objGenericPagination;
if (response.HasNextPage)
{
nextRoute = $"/mandates?page={(page + 1)}";
response.NextPageUrl = _uriPaginationService.GetPaginationUri(page, nextRoute).ToString();
}
else
{
response.NextPageUrl = null;
}
if (response.HasPreviousPage)
{
previousRoute = $"/mandates?page={(page - 1)}";
response.PreviousPageUrl = _uriPaginationService.GetPaginationUri(page, previousRoute).ToString();
}
else
{
response.PreviousPageUrl = null;
}
return response;
}
public async Task<IEnumerable<Mandate>> GetMandates()
{
return await _unitOfWork.MandateRepository.GetAll();
}
startup.cs:
services.AddTransient<IMandateService, MandateService>();
Controller:
[Produces("application/json")]
[ApiController]
[ApiVersion("1.0")]
public class AdminController : ControllerBase
{
private readonly IMerchantService _merchantService;
private readonly DDMDbContext _context;
public AdminController(DDMDbContext context, IMerchantService merchantService)
{
_merchantService = merchantService;
_context = context;
}
[HttpGet("mandates")]
[Authorize]
public async Task<ResponsePagination<GenericPagination<MandateGetDto>>> GetAllMyMandates(int page, int sizeByPage)
{
return await _mandateService.GetAll(page, sizeByPage);
}
}
When I used POSTMAN for the Get Request, I got this response:
{
"current_page": 0,
"page_size": 0,
"total_pages": -2147483648,
"total_records": 1,
"has_next_page": false,
"has_previous_page": false,
"data": []
}
Data is blank while total record is 1.
How do I resolve this?
Thanks
You have not shown us the principal part of your code, which is the controller
Controller is the reason why your web API even works. So, if you have misconfigured something, it should be present in the controller first or then somewhere else.
Show us the code for the controller.
Edit
I am not sure if DbSet is appropriate for the usage, but using the context object works for me.
You should use
_context.MandateOrWhateverElseItIs.ToListAsync();
instead of using
_entities.ToListAsync();
Using the DbSet can be an issue, I recommend using the context. My application works fruitfully with context.
Edit
This is your code in BaseRepository
public class BaseRepository<T> : IBaseRepository<T> where T : AuditableBaseEntity
{
private readonly DDMDbContext _context;
private DbSet<T> _entities;
public BaseRepository(DDMDbContext context)
{
_context = context;
_entities = context.Set<T>();
}
public async Task<IEnumerable<T>> GetAll()
{
var list = await _entities.ToListAsync();
return list;
}
public bool EntityExists(long id)
{
return _entities.Any(x => x.Id == id);
}
}
What you should change it to is
public class BaseRepository<T> : IBaseRepository<T> where T : AuditableBaseEntity
{
private readonly DDMDbContext _context;
private DbSet<T> _entities;
public BaseRepository(DDMDbContext context)
{
_context = context;
_entities = context.Set<T>();
}
public async Task<IEnumerable<T>> GetAll()
{
//Changes are here
var list = await _context.EntitiesOrWhateverElseItIs.ToListAsync(); //I don't know what the option is, you can look it inside the autocomplete. Be sure to change EntitiesOrWhateverElseItIs with the option you see in autocomplete menu
return list;
}
public bool EntityExists(long id)
{
return _entities.Any(x => x.Id == id);
}
}

ASP.NET Core - System.InvalidOperationException: Unable to resolve service for type while attempting to activate

In my ASP.NER Core Web API Project, I have this code:
public interface IUriPaginationService
{
public Uri GetPaginationUri(int page, string actionUrl);
}
public class UriPaginationService : IUriPaginationService
{
private readonly string _baseUri;
public UriPaginationService(string baseUri)
{
_baseUri = baseUri;
}
public Uri GetPaginationUri(int page, string actionUrl)
{
string baseUrl = $"{_baseUri}{actionUrl}";
return new Uri(baseUrl);
}
}
public abstract class AuditableBaseEntity
{
public AuditableBaseEntity()
{
CreatedDate = DateTime.Now;
}
[Key]
public virtual long Id { get; set; }
[JsonIgnore]
public bool IsDeleted { get; set; }
[DataType(DataType.DateTime)]
public DateTime? CreatedDate { get; set; }
public long? LastUpdatedBy { get; set; }
}
Repositories:
public interface IBaseRepository<T> where T : AuditableBaseEntity
{
Task<IEnumerable<T>> GetAll();
Task<T> GetById(long id);
bool EntityExists(long id);
}
public class BaseRepository<T> : IBaseRepository<T> where T : AuditableBaseEntity
{
private readonly DDMDbContext _context;
private DbSet<T> _entities;
public BaseRepository(DDMDbContext context)
{
_context = context;
_entities = context.Set<T>();
}
public async Task<IEnumerable<T>> GetAll()
{
var list = await _entities.Where(x => x.IsDeleted == false).ToListAsync();
return list;
}
public async Task<T> GetById(long id)
{
return await _entities.FindAsync(id);
}
public bool EntityExists(long id)
{
return _entities.Any(x => x.Id == id && x.IsDeleted == false);
}
}
UnitOfWork:
public interface IUnitOfWork : IDisposable
{
IBaseRepository<Merchant> MerchantRepository { get; }
}
public class UnitOfWork : IUnitOfWork
{
private readonly DDMDbContext _context;
public UnitOfWork(DDMDbContext context)
{
_context = context;
}
private readonly IBaseRepository<Merchant> _merchantRepository;
public IBaseRepository<Merchant> MerchantRepository => _merchantRepository ?? new BaseRepository<Merchant>(_context);
public void Dispose()
{
if (_context != null)
{
_context.Dispose();
}
}
}
Services:
public interface IMerchantService
{
public Task<IEnumerable<Merchant>> GetMerchants();
public bool EntityExists(long id);
public Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage);
}
public class MerchantService : IMerchantService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IUriPaginationService _uriPaginationService;
private readonly DDMDbContext _context;
public MerchantService(IUnitOfWork unitOfWork, IUriPaginationService uriPaginationService, DDMDbContext context)
{
_unitOfWork = unitOfWork;
_uriPaginationService = uriPaginationService;
_context = context;
}
public async Task<IEnumerable<Merchant>> GetMerchants()
{
return await _unitOfWork.MerchantRepository.GetAll();
}
public async Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage)
{
string nextRoute = null, previousRoute = null;
IEnumerable<Merchant> data = await _unitOfWork.MerchantRepository.GetAll();
var mapper = new EntityMapper();
var merchantsDto = data.Select(m => mapper.FromMerchantToMerchantGetDto(m)).ToList();
GenericPagination<MerchantGetDto> objGenericPagination = GenericPagination<MerchantGetDto>.Create(merchantsDto, page, sizeByPage);
ResponsePagination<GenericPagination<MerchantGetDto>> response = new ResponsePagination<GenericPagination<MerchantGetDto>>(objGenericPagination);
response.CurrentPage = objGenericPagination.CurrentPage;
response.HasNextPage = objGenericPagination.HasNextPage;
response.HasPreviousPage = objGenericPagination.HasPreviousPage;
response.PageSize = objGenericPagination.PageSize;
response.TotalPages = objGenericPagination.TotalPages;
response.TotalRecords = objGenericPagination.TotalRecords;
response.Data = objGenericPagination;
if (response.HasNextPage)
{
nextRoute = $"/merchants?page={(page + 1)}";
response.NextPageUrl = _uriPaginationService.GetPaginationUri(page, nextRoute).ToString();
}
else
{
response.NextPageUrl = null;
}
if (response.HasPreviousPage)
{
previousRoute = $"/merchants?page={(page - 1)}";
response.PreviousPageUrl = _uriPaginationService.GetPaginationUri(page, previousRoute).ToString();
}
else
{
response.PreviousPageUrl = null;
}
return response;
}
public bool EntityExists(long id)
{
return _unitOfWork.MerchantRepository.EntityExists(id);
}
public async Task<Merchant> GetById(long id)
{
return await _unitOfWork.MerchantRepository.GetById(id);
}
}
Controller:
[Produces("application/json")]
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AdminController : ControllerBase
{
private readonly IMerchantService _merchantService;
public AdminController(MerchantService merchantService)
{
_merchantService = merchantService;
}
[HttpGet("merchants")]
public async Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage)
{
return await _merchantService.GetAll(page, sizeByPage);
}
}
startup:
public void ConfigureServices(IServiceCollection services)
{
// services.AddMvc();
services.AddControllers();
services.AddDb(Configuration);
services.AddJwtAuthentication(Configuration);
services.AddMvcCoreFramework(Configuration);
services.AddAppAuthorization(Configuration);
services.AddControllersWithViews();
services.AddRazorPages();
services.AddVersioning();
services.AddSwagger();
services.AddRouting(options => options.LowercaseUrls = true);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IUriPaginationService>(provider =>
{
var accesor = provider.GetRequiredService<IHttpContextAccessor>();
var request = accesor.HttpContext.Request;
var absoluteUri = string.Concat(request.Scheme, "://", request.Host.ToUriComponent());
return new UriPaginationService(absoluteUri);
});
services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddTransient<IMerchantService, MerchantService>();
}
When I use this on postman get request:
https://localhost:44341/api/v1/merchant/mandates
I got this error:
System.InvalidOperationException: Unable to resolve service for type 'API.Infrastructure.Services.Concrete.MerchantService' while attempting to activate 'API.Web.Controllers.v1.MerchantController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
How do I resolve this:
Thanks
The controller is dependent on the implementation (class)
public AdminController(MerchantService merchantService)
{
_merchantService = merchantService;
}
while you registered the abstraction (interface).
services.AddTransient<IMerchantService, MerchantService>();
Based on the registration it is most likely the controller was meant to be dependent on the interface (abstraction)
public AdminController(IMerchantService merchantService) //<-- CHANGED TO INTERFACE
{
_merchantService = merchantService;
}
Updating the controller constructor to be dependent on the registered abstraction will fix the shown exception.
in addition to Nkosi answer, the three injection service are listed below and their scope. three methods define the lifetime of the services
AddTransient
Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.
AddScoped
Scoped lifetime services are created once per request.
AddSingleton
Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the same instance.
Brief explation can be found here

NSubstitute and AsQuerable not returning results

I have a strange issue.
I am creating a generic class and I have a generic method and test. The test looks like this:
[Test]
public async Task ReturnGeneric()
{
// Assemble
const int id = 1;
var request = new GetGeneric<Venue>(id);
var services = GetGenericContext.GivenServices();
var handler = services.WhenCreateHandler();
var venues = Builder<Venue>.CreateListOfSize(20).Build().ToDbSet();
services.DatabaseContext.Set<Venue>().Returns(venues);
// Act
var response = await handler.Handle(request, CancellationToken.None);
// Assert
response.Success.Should().BeTrue();
response.Error.Should().BeNull();
response.Result.Should().BeOfType<Venue>();
}
}
And the method looks like this:
public async Task<Attempt<T>> Handle(GetGeneric<T, TKey> request, CancellationToken cancellationToken)
{
var id = request.Id;
if (EqualityComparer<TKey>.Default.Equals(id, default)) return ValidationError.Required(nameof(id));
var generics = _databaseContext.Set<T>().AsQueryable();
var t = _databaseContext.Set<T>().ToList();
var generic = generics.SingleOrDefault(m => m.Id.Equals(request.Id));
var x = t.SingleOrDefault(m => m.Id.Equals(id));
if (generic == null) return NotFoundError.ItemNotFound(nameof(T), request.Id.ToString());
return generic;
}
variables t and x are just tests for my own sanity.
The issue here is that generic is null in my test, but x is not.
It seems to have a problem with the AsQueryable() method. For some reason if I do a call to AsQueryable() there are no results in the collection, but there are if it invoke ToList().
This is my extension method for ToDbSet():
public static class DbSetExtensions
{
public static DbSet<T> ToDbSet<T>(this IEnumerable<T> data) where T : class
{
var queryData = data.AsQueryable();
var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
((IQueryable<T>)dbSet).Provider.Returns(queryData.Provider);
((IQueryable<T>)dbSet).Expression.Returns(queryData.Expression);
((IQueryable<T>)dbSet).ElementType.Returns(queryData.ElementType);
((IQueryable<T>)dbSet).GetEnumerator().Returns(queryData.GetEnumerator());
return dbSet;
}
}
Can anyone think of a reason why this is not working?
The entire class looks like this:
public class GenericGet<T, TKey> : IRequest<Attempt<T>> where T: TClass<TKey>
{
public TKey Id { get; }
public GenericGet(TKey id)
{
Id = id;
}
}
public class GenericGet<T> : GenericGet<T, int> where T : TClass<int>
{
public GenericGet(int id) : base(id)
{
}
}
public class GenericGetHandler<T, TKey> : IRequestHandler<GenericGet<T, TKey>, Attempt<T>> where T: TClass<TKey>
{
private readonly DatabaseContext _databaseContext;
public GenericGetHandler(DatabaseContext databaseContext)
{
_databaseContext = databaseContext;
}
public async Task<Attempt<T>> Handle(GenericGet<T, TKey> request, CancellationToken cancellationToken)
{
var id = request.Id;
if (EqualityComparer<TKey>.Default.Equals(id, default)) return ValidationError.Required(nameof(id));
var generics = _databaseContext.Set<T>().AsQueryable();
var generic = generics.SingleOrDefault(m => m.Id.Equals(request.Id));
if (generic == null) return NotFoundError.ItemNotFound(nameof(T), request.Id.ToString());
return generic;
}
}
public class GenericGetHandler<T> : GenericGetHandler<T, int> where T : TClass<int>
{
public GenericGetHandler(DatabaseContext databaseContext) : base(databaseContext)
{
}
}
And a venue looks like this:
public class Venue: TClass<int>
{
[Required, MaxLength(100)] public string Name { get; set; }
[MaxLength(255)] public string Description { get; set; }
public IList<Theatre> Theatres { get; set; }
}
I changed my DatabaseContext mock to actually use the in memory provider as suggested by Fabio.
It looks like this:
public class DatabaseContextContext
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
var options = new DbContextOptionsBuilder<DatabaseContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.EnableSensitiveDataLogging()
.Options;
DatabaseContext = new DatabaseContext(options);
}
}
And then my GetGenericContext looks like this:
public class GenericGetContext<T> : DatabaseContextContext where T : TClass<int>
{
public static GenericGetContext<T> GivenServices() => new GenericGetContext<T>();
public GenericGetHandler<T> WhenCreateHandler() => new GenericGetHandler<T>(DatabaseContext);
}
Instead of doing:
services.DatabaseContext.Set<Venue>().Returns(venues);
We are not mocking anymore, so we can actually do:
services.DatabaseContext.Venues.AddRange(venues);
services.DatabaseContext.SaveChanges();
We must call save changes otherwise it won't actually say the venues to the collection.
Once you do that, everything works as expected.

Moq Generic Repository Pattern

I have a generic services which are calling generic repository. I need to manage unit test, but not able to do it. May you help me ?
public class EntityService<TEntity> : IEntityService<TEntity> where TEntity : class, new()
{
private readonly IRepositoryAsync<TEntity> _repository;
public EntityService(IRepositoryAsync<TEntity> repository)
{
_repository = repository;
}
public virtual IQueryable<TEntity> Entities => Queryable();
public virtual bool Delete(object id)
{
if (id == null)
throw new ArgumentNullException(nameof(id));
TEntity entity = _repository.Find(id);
if (entity != null)
return Delete(entity);
return false;
}
}
GENERIC REPOSITORY
public class Repository<TEntity> : IRepositoryAsync<TEntity> where TEntity : class, new()
{
private readonly IDataContextAsync _context;
private readonly DbSet<TEntity> _dbSet;
public Repository(IDataContextAsync context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
if (context is DbContext dbContext)
_dbSet = dbContext.Set<TEntity>();
}
public virtual void Delete(object id)
{
TEntity entity = _dbSet.Find(id);
Delete(entity);
}
}
What I tried is next:
I had create abstract generic test
public abstract class EntityServiceUnitTests<TEntity> where TEntity : class, IEntity,new()
{
private readonly IEntityService<TEntity> _service;
public EntityServiceUnitTests()
{
_service = CreateSystemUnderTest();
}
[Test]
[TestCase("299cd2b5-ab47-4006-9a47-c85e4770e9b1")]
public void Delete_EntityWithExistUniqueIdentifier_ReturnsTrue(Guid id)
{
bool response = _service.Delete(id);
Assert.True(response);
}
protected abstract IEntityService<TEntity> CreateSystemUnderTest();
}
Than I had implement concrete for unit test
public class ConcreteEntityServiceUnitTests : EntityServiceUnitTests<Data>
{
protected override IEntityService<Data> CreateSystemUnderTest()
{
MockBehavior behavior = MockBehavior.Strict;
Mock<IRepositoryAsync<Data>> repoMock = new Mock<IRepositoryAsync<Data>>(behavior);
repoMock.Setup(s => s.Queryable()).Returns(DataList().AsQueryable);
SetupService();
IEntityService<Data> entityService = new EntityService<Data>(repoMock.Object);
return entityService;
}
private void SetupService()
{
Mock<IEntityService<Data>> service = new Mock<IEntityService<Data>>();
service.Setup(s => s.Find(It.Is<Data>(f => f.Id == It.IsAny<Guid>()))).Returns(DataList().FirstOrDefault(w => w.Id == It.IsAny<Guid>()));
}
private IList<Data> DataList()
{
List<Data> dataList = new List<Data>();
dataList.Add(new Data
{
Id = new Guid("299cd2b5-ab47-4006-9a47-c85e4770e9b1"),
ObjectState = ObjectState.Added
});
dataList.Add(new Data
{
Id = new Guid("229cd2b5-ab47-4006-9a47-c85e4770e9b1"),
ObjectState = ObjectState.Added
});
return dataList;
}
}
As error I'm getting:
Moq.MockException :
IRepository<Data>.Find([299cd2b5-ab47-4006-9a47-c85e4770e9b1])
invocation failed with mock behavior Strict.

How do I setup this in Moq to give me null or an object?

I want to saw that I do not care what is in the Find clause. Just give me null.
Here is the test
[Fact]
public void VerifyIndexViewType()
{
// Arrange
var mockUserProvider = new Mock<IUserProvider>();
mockUserProvider.Setup(x => x.GetUserId()).Returns("any-value-here");
var mockUnitOfWork = new Mock<IUnitOfWork>();
//how would I just return an object or null for example.. this doesnt work
// mockUnitOfWork.Setup(x => x.UserProfileDataRepository.Find(u => u.ApplicationUserId == "any value here")).Returns((IRepository<UserProfileData>)null);
var controller = new ProfileController(mockUnitOfWork.Object, mockUserProvider.Object);
// Act
var result = controller.Update();
// Assert
Assert.IsType<ViewResult>(result);
}
For the following controller and action
public class ProfileController : BaseController
{
private IUnitOfWork _unitOfWork;
private readonly IUserProvider _requestUserProvider;
public ProfileController(IUnitOfWork unitOfWork,
IUserProvider requestUserProvider)
: base(unitOfWork, requestUserProvider)
{
_unitOfWork = unitOfWork;
_requestUserProvider = requestUserProvider;
}
public IActionResult Update()
{
//this is easy
string userId = _requestUserProvider.GetUserId();
//how do I do the setup in moq for this?
IEnumerable<UserProfileData> userProfileQuestions = _unitOfWork.UserProfileDataRepository.Find(x => x.ApplicationUserId == userId);
if (userProfileQuestions != null)
{
ProfileViewModel profileViewModel = new ProfileViewModel();
profileViewModel.UserProfileData = userProfileQuestions.FirstOrDefault();
return View(profileViewModel);
}
return View("Error", "Home");
}
EDIT 1: MY IUnitOfWork and implementation of the method
public interface IUnitOfWork
{
IRepository<ApplicationUser> ApplicationUserRepository { get; }
IRepository<RefMedicalSpecialty> RefMedicalSpecialtyRepository { get; }
IRepository<RefProgramDetailData> RefProgramDetailDataRepository { get; }
IRepository<RefProgramProfileData> ProgramProfileDataRepository { get; }
IRepository<UserProgram> UserProgramRepository { get; }
IRepository<UserFeedback> UserFeedbackRepository { get; }
IRepository<UserAction> UserActionRepository { get; }
IRepository<UserProfileData> UserProfileDataRepository { get; }
IRepository<RawCredential> RawCredentialRepository { get; }
IRepository<RefProgramCharacteristic> RefProgramCharacteristicRepository { get; }
IRepository<UserProgramRefProgramCharacteristic> UserProgramRefProgramCharacteristicRepository { get; }
void Commit();
void RejectChanges();
void Dispose();
}
public IRepository<UserProfileData> UserProfileDataRepository =>
new Repository<UserProfileData>(_retContext);
Declare the Method Find as virtual
public virtual YourType Find(Expression<Func<YourClass, bool>> yourfunc)
and the mock as:
mockUnitOfWork.Setup(x => x.UserProfileDataRepository.Find(It.IsAny<Expression<Func<YourClass, bool>>>()).Returns(DefineYourReturn);

Categories

Resources