Home > Enterprise >  Why my mock object not working truly in xUnit test project?
Why my mock object not working truly in xUnit test project?

Time:12-15

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"
            };
        }
    }

`

CodePudding user response:

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

CodePudding user response:

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