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;
}
}
我正在尝试测试下面的函数,以获取将使用关系谓词桶的所有活动类别。初始化程序 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;
}
}