RelationPredicateBucket 不会为存储库 GetAllActive() 调用的单元测试过滤模拟数据

RelationPredicateBucket doesn't filter mocked data for Unit Test on Repository GetAllActive() call

我正在尝试测试下面的函数,以获取将使用关系谓词桶的所有活动类别。初始化程序 class 中的模拟数据添加了三个活动且未删除的对象。它在已删除且未激活的末尾添加四分之一。

在测试期间,调用将 return 所有四个对象,而不是预期的三个对象。这就是我坚持的地方。

我曾尝试将 _randomCategories 作为可查询对象,但这也失败了。

第一个 class 中有很多代码,因此可能很难理解,因此每个部分都分成区域说明它执行的部分,即测试设置、模拟数据和测试他们自己。

模拟数据区域是预期的结果。对于我的需求可能不是必需的,因为除了获得预期的计数外,它没有被用于此,但它可能与测试的整体结构有关。

CategoryServiceTests.cs

#region Test Setup

public class CategoryServiceFixture : IDisposable
{
    public CategoryService Sut { get; private set; }
    private SystemRepository SystemRepository { get; set; }
    private Mock<CategoryRepository> _categoryRepositoryMock;
    private List<CategoryEntity> _randomCategories;

    public CategoryServiceFixture()
    {
        // Init Category List
        _randomCategories = CategoryEntityInitializer.GetAllMockCategories();

        // Init repository
        _categoryRepositoryMock = new Mock<CategoryRepository>(new object[] { null });

        // Setup mocking behavior            
        // BaseRepository
        _categoryRepositoryMock
            .Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
            .Returns(_randomCategories);

        SystemRepository = new SystemRepository(category: _categoryRepositoryMock.Object);
        Sut = new CategoryService(this.SystemRepository);
    }

    public void Dispose()
    {
        //Sut.Dispose();
    }
}

[CollectionDefinition("CategoryService Collection")]
public class CategoryServiceCollection : ICollectionFixture<CategoryServiceFixture> { }

#endregion

#region Mock Data

public static class CategoryRepositoryMockData
{
    public static IEnumerable<object> GetCategories
    {
        get
        {
            yield return new object[] { 1, new List<CategoryEntity>() {
                new CategoryEntity
                {
                    CategoryId = 1,
                    Name = "Test1",
                    IsDeleted = false,
                    IsActive = true
                },
                new CategoryEntity
                {
                    CategoryId = 2,
                    Name = "Test2",
                    IsDeleted = false,
                    IsActive = true
                },
                new CategoryEntity
                {
                    CategoryId = 3,
                    Name = "Test3",
                    IsDeleted = false,
                    IsActive = true
                }
            }};
        }
    }
}

#endregion

#region Tests

[Collection("CategoryService Collection")]
public class CategoryServiceTests
{
    private CategoryServiceFixture _fixture;

    public CategoryServiceTests(CategoryServiceFixture fixture)
    {
        _fixture = fixture;
    }

    [Theory]
    [Trait("Category", "Get All Active Categories")]
    [Trait("Expected", "Return Correct")]
    [MemberData("GetCategories", MemberType = typeof(CategoryRepositoryMockData))]
    public void GetActiveCategories_ShouldReturn(int id, IList<CategoryEntity> expectedCategoryObjects)
    {
        var result = _fixture.Sut.GetActiveCategories();
        Assert.Equal(expectedCategoryObjects.Count, result.Count);
    }
}

#endregion

这 class 生成模拟数据库对象。这是应该搜索的内容,select 列表中的正确内容。

CategoryEntityInitializer.cs

public static class CategoryEntityInitializer
{
    public static List<CategoryEntity> GetAllMockCategories()
    {
        List<CategoryEntity> _categories = new List<CategoryEntity>();

        for (var i = 1; i <= 3; i++)
        {
            var entity = new CategoryEntity()
            {
                CategoryId = i,
                Name = String.Format("{0}{1}", "Test", i),
                IsDeleted = false,
                IsActive = true
            };

            _categories.Add(entity);
        }

        var lastEntity = new CategoryEntity()
        {
            CategoryId = 4,
            Name = String.Format("{0}{1}", "Test", 4),
            IsDeleted = true,
            IsActive = false
        };

        _categories.Add(lastEntity);

        return _categories;
    }
}

这个class就是谓词所在的地方。

CategoryService.cs

public class CategoryService : BaseService
{
    public IList<CategoryModel> GetActiveCategories()
    {
        var bucket = new RelationPredicateBucket();
        bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
        bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
        var categoriesEntities = _systemRepository.Category.GetAll(bucket);
        return CategoryMapper.MapToModels(categoriesEntities);
    }
}

代码结构的其余部分适用于所有其他测试和跨不同测试 classes。这是我第一次不得不测试关系谓词桶。

更新 18/05/16

我找到了问题的解决方案。在下面的代码中回答。

_categoryRepositoryMock
    .Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
    .Returns(new Func<IRelationPredicateBucket, IDataAccessAdapter, IEnumerable<CategoryEntity>>(
        (bucket, adapter) => _randomCategories.Where(a => a.IsDeleted == false && a.IsActive == true)));

旧答案 2016 年 11 月 5 日

I believe I have found part of the answer. In mocking the repository, I was returning all four objects, no matter if the predicate bucket would work or not.

_categoryRepositoryMock
    .Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
    .Returns(_randomCategories);

这将导致它 return 所有四个,因为我没有实施桶来过滤掉匹配项。我认为 .Returns 会将数据放入存储库,就好像 return 从数据库中提取数据,然后使用存储桶进行过滤。

我发现对存储库的调用不会转到正常 运行 时应该调用的存储库,而是转到模拟存储库,这是您需要过滤的地方要 returned 的数据。

需要做类似的事情。

_categoryRepositoryMock
    .Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
    .Returns(
        (IRelationPredicateBucket bucket) => _randomCategories.Where(x => x.Name.Equals(bucket)));

Although this still give me a problem as I don't know how to get inside the bucket to match to the list, it is at least heading in the correct direction.

注意:我也通过搜索发现这种失败的另一个原因是代码,在这种情况下被调用的函数太复杂而无法测试.它应该被分成更小的卡盘,以使其不那么复杂,并单独测试每个部分。

之前

public class CategoryService : BaseService
{
    public IList<CategoryModel> GetActiveCategories()
    {
        var bucket = new RelationPredicateBucket();
        bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
        bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
        var categoriesEntities = _systemRepository.Category.GetAll(bucket);
        return CategoryMapper.MapToModels(categoriesEntities);
    }
}

之后

public class CategoryService : BaseService
{
    public IList<CategoryModel> GetActiveCategories()
    {
        var bucket = GetActiveCategoriesBucket();
        var categoriesEntities = _systemRepository.Category.GetAll(bucket);
        return CategoryMapper.MapToModels(categoriesEntities);
    }

    public RelationPredicateBucket GetActiveCategoriesBucket()
    {
        var bucket = new RelationPredicateBucket();
        bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
        bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
        return bucket;
    }
}