c# - 试图模拟 IQueryable 实体框架查询
问题描述
我正在尝试测试查询是否不区分大小写。此生产代码有效:
public ILookup<string, EEntry> GetEEntries(int batchId, List<string> employeeIds)
{
using (WithNoLock())
{
var result = from e in _entities.EEntries
where e.CPayBatchProcessId == batchId
&& (!e.Blocked.HasValue || e.Blocked.Value != true)
&& employeeIds.Contains(e.Id)
select e;
return result.ToLookup(e => e.Id, StringComparer.OrdinalIgnoreCase);
}
}
我无法让单元测试工作。我的第一次尝试失败了,因为我相信该列表IEnumerable
不是IQueryable
. 但是,我的尝试并IQueryable
没有通过。该查询区分大小写,我不希望这样。这就是我所做的IQueryable
:
[TestCase("abc", "ABC")]
public void EEntriesAreCaseInsensitive(string employeeId1Input, string employeeId1Output)
{
var payEntries = new List<EEntry>
{
new EEntry() {CPayBatchProcessId = 8, Id = employeeId1Input},
new EEntry() {CPayBatchProcessId = 8, Id = "123"}
}.AsQueryable();
var payEntriesDbSet = new Mock<DbSet<EEntry>>();
payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.Provider).Returns(payEntries.Provider);
payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.Expression).Returns(payEntries.Expression);
payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.ElementType).Returns(payEntries.ElementType);
payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.GetEnumerator()).Returns(payEntries.GetEnumerator);
var context = new Mock<ISomeContext>();
context.Setup(x => x.EEntries).Returns(payEntriesDbSet.Object);
var employeeIds = new List<string>() { "aBc", "dEf", "gHi" };
var repo = new EEntriesRepository(context.Object);
var payEntryRecords = repo.GetEEntries(8, employeeIds);
Assert.IsTrue(payEntryRecords.Contains(employeeId1Output));
}
我错过了什么?
注意: EEntry.Id 的 getter 返回.ToUpper()
. 生产代码正确地忽略了这一点。测试代码没有。
解决方案
字符串比较不区分大小写的性质取决于您的数据库提供程序。SQL Server 将比较字符串不区分大小写,而我相信 PostgreSQL 之类的则不会。
因此,如果您的代码逻辑确实如此employeeIds.Contains(e.Id)
,EF 会将等效逻辑传递给数据库。当用 Mock 和 替换它时List<T>.AsQueryable()
,C# 会将字符串视为区分大小写,而 SQL Server 不关心。IN() 子句和字符串比较不区分大小写。
我会考虑使用以下或类似的方法来确保执行字符串比较不区分大小写。这应该适用于数据库提供程序,并且可以更好地处理模拟数据。
public ILookup<string, EEntry> GetEEntries(int batchId, List<string> employeeIds)
{
if(employeeIds == null) throw new ArgumentNullException("employeeIds");
employeeIds = employeeIds.ConvertAll(x => x.ToUpper());
using (WithNoLock())
{
var result = from e in _entities.EEntries
where e.CPayBatchProcessId == batchId
&& (!e.Blocked.HasValue || e.Blocked.Value != true)
&& employeeIds.Contains(e.Id.ToUpper())
select e;
return result.ToLookup(e => e.Id, StringComparer.OrdinalIgnoreCase);
}
}
推荐阅读
- python - Flask:如果字段不存在,则 current_app AttributeError
- amazon-web-services - SQS FIFO 如何确保只处理一次?
- pine-script - 为什么我的 label.new 函数只能返回几个月?
- perl - perl中参数太多的函数
- android - 似乎已设置 BLE 通知,但在 Android 上未收到任何通知
- c++ - 有没有办法对函数进行模板化,以便可以输入 N 维大括号初始值设定项列表?
- c# - 实体类型“AspNetUserLogins”需要定义主键吗?
- machine-learning - 自编码器应该是对称的吗?
- google-apps-script - 删除 Google 表格上的脚本所需的授权
- c# - 我有这个问题不是所有的代码路径都返回一个值