如何模拟IRepository <t>?

时间:2015-08-25 04:23:30

标签: c# unit-testing unit-of-work

我想在内部使用存储库模拟一个工作单元接口以进行单元测试。到目前为止,我能够像下面这样做。

namespace Liquid.Service.UnitTest
{
    using Liquid.DataAccess.Interface;
    using Liquid.Domain;
    using Domain.Interface;
    using Moq;
    using System.Collections.Generic;
    using System.Linq;

    internal class Helper
    {
        internal Mock<IUnitOfWork> MockUnitOfWork(ICollection<Dummy> dummies = null,
            ICollection<ProductType> productTypes = null)
        {
            dummies = dummies ?? new List<Dummy>();
            productTypes = productTypes ?? new List<ProductType>();

            var dummyRepositoryMock = MockDummyRepository(dummies);
            var productTypeRepositoryMock = MockProductTypeRepository(productTypes);

            var unitOfWorkMock = new Mock<IUnitOfWork>();
            unitOfWorkMock.Setup(x => x.DummyRepository)
                .Returns(dummyRepositoryMock.Object);
            unitOfWorkMock.Setup(x => x.ProductTypeRepository)
                .Returns(productTypeRepositoryMock.Object);

            return unitOfWorkMock;
        }

        private Mock<IDummyRepository> MockDummyRepository(ICollection<Dummy> dummies)
        {
            var dummyRepositoryMock = new Mock<IDummyRepository>();

            dummyRepositoryMock.Setup(x => x.FindById(It.IsAny<int>()))
                .Returns((int arg1) => dummies.Where(x => x.Id == arg1).SingleOrDefault());

            dummyRepositoryMock.Setup(x => x.Add(It.IsAny<Dummy>()))
                .Callback((Dummy arg1) => dummies.Add(arg1));

            return dummyRepositoryMock;
        }

        private Mock<IProductTypeRepository> MockProductTypeRepository(ICollection<ProductType> productTypes)
        {
            var productTypeRepositoryMock = new Mock<IProductTypeRepository>();

            productTypeRepositoryMock.Setup(x => x.FindById(It.IsAny<int>()))
                .Returns((int arg1) => productTypes.SingleOrDefault(x => x.Id == arg1));

            productTypeRepositoryMock.Setup(x => x.Add(It.IsAny<ProductType>()))
                .Callback((ProductType arg1) => productTypes.Add(arg1));

            return productTypeRepositoryMock;
        }
    }
}

你知道我已经创建了两个模拟DummyRepository和ProductTypeRepository的方法,但由于它有相同的实现,我认为它对我拥有的每个存储库都是多余的。 下面是Repositories和IRepository代码。

namespace Liquid.DataAccess.Interface
{
    using Liquid.Domain;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;

    public interface IDummyRepository : IRepository<Dummy>
    {
    }

    public interface IProductTypeRepository : IRepository<ProductType>
    {
    }

    public interface IRepository<TEntity> where TEntity : class
    {
        IList<TEntity> GetAll();

        Task<List<TEntity>> GetAllAsync();

        Task<List<TEntity>> GetAllAsync(CancellationToken cancellationToken);

        IList<TEntity> PageAll(int skip, int take);

        Task<List<TEntity>> PageAllAsync(int skip, int take);

        Task<List<TEntity>> PageAllAsync(CancellationToken cancellationToken, int skip, int take);

        TEntity FindById(object id);

        Task<TEntity> FindByIdAsync(object id);

        Task<TEntity> FindByIdAsync(CancellationToken cancellationToken, object id);

        void Add(TEntity entity);

        void Update(TEntity entity);

        void Remove(TEntity entity);
    }
}

如何使用相同的方法来模拟继承IRepository的每个存储库实现?

更新: 测试只是一个简单的添加和检查,如下所示。

    [Test]
    public void ProductTypeService_Add()
    {
        // GIVEN
        var productTypeData = new ProductType()
        {
            Id = 1,
            Description = "ProductType1"
        };

        // WHEN
        var unitOfWorkMock = new Helper().MockUnitOfWork();
        var productTypeService = new ProductTypeService(unitOfWorkMock.Object);
        productTypeService.Add(productTypeData);
        unitOfWorkMock.Verify(x => x.SaveChanges());

        // THEN
        Assert.That(productTypeService.FindById(1) != null);
        Assert.That(productTypeService.FindById(2) == null);

        // WHEN
        var productTypeData2 = new ProductType()
        {
            Id = 2,
            Description = "ProductType2"
        };

        productTypeService.Add(productTypeData2);

        // THEN
        Assert.That(productTypeService.FindById(2) != null);
    }

1 个答案:

答案 0 :(得分:1)

我认为你的问题过于复杂,因此也解决了问题。如果您没有为其添加任何值,则不需要各种存储库的接口,如 IDummyRepository IProductRepository

您的数据类

public class Dummy
{
    public int Id { get; set; }
}

public class ProductType
{
    public int Id { get; set; }
}

您的ProductTypeService(我只能假设这一点)

public class ProductTypeService
{
    private readonly IUnitOfWork _unitOfWork;

    public ProductTypeService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public void AddProductType(ProductType productType)
    {
        _unitOfWork.ProductTypes.Add(productType);
    }
}

您的IUnitOfWork

public interface IUnitOfWork
{
    IRepository<Dummy> Dummies { get; set; }
    IRepository<ProductType> ProductTypes { get; set; }
}

您的IRepository保持不变,因此我不会将其粘贴到此处!

最后你的单元测试

[TestFixture]
public class Class1
{
    private Mock<IUnitOfWork> _unitOfWorkMock;
    private Mock<IRepository<Dummy>> _dummyRepositoryMock;
    private Mock<IRepository<ProductType>> _productTypeRepositoryMock;

    [SetUp]
    public void Setup()
    {
        _unitOfWorkMock = new Mock<IUnitOfWork>();
        _dummyRepositoryMock = CreateMock<Dummy>();
        _productTypeRepositoryMock = CreateMock<ProductType>();

        _unitOfWorkMock.Setup(u => u.Dummies).Returns(_dummyRepositoryMock.Object);
        _unitOfWorkMock.Setup(u => u.ProductTypes).Returns(_productTypeRepositoryMock.Object);
    }

    [Test]
    public void product_type_service_should_add_item_to_the_underlying_repository()
    {
        var productTypeService = new ProductTypeService(_unitOfWorkMock.Object);
        var productType = new ProductType {Id = 10};
        productTypeService.AddProductType(productType);
        _productTypeRepositoryMock.Verify(r => r.Add(It.Is<ProductType>(p => p.Id == productType.Id)), Times.Once());
    }

    private Mock<IRepository<T>> CreateMock<T>() where T : class
    {
        var mock = new Mock<IRepository<T>>();

        // do more common magic here

        return mock;
    }
}