我有一个服务层,它调用存储库层来获取数据,然后对返回对象进行操作。我想测试发送到存储库的表达式" get"方法,比如主键成为复合键或其他东西。
示例:
public async Task ArchiveAsync(Domain.Person person)
{
Data.Person entityModel = await _repo.SingleOrDefaultAsync<Data.Person>(p => p.Id == person.Id);
// Stuff is done here...
}
因此,在此示例中,传入域对象,获取数据对象,并对其执行某些操作。我想测试传递给SingleOrDefaultAsync
方法的表达式。
思想?
答案 0 :(得分:2)
重构代码并制作&#34;表达式可能更好。一个合适的实体。 Specification模式非常适合您的情况。
Vladimir Khorikov撰写了一篇非常简单的文章:Specification pattern: C# implementation
他在GitHub上发布了一个示例项目here
如果链接无效,我在这里添加主核心逻辑 您的存储库将如下所示:
public IReadOnlyList<T> Find(Specification<T> specification)
{
using (context))
{
return context.DbSet<T>()
.Where(specification.ToExpression())
.ToList();
}
}
对于Specification类,您可以找到许多实现 它是一个小的实用程序类,最终转换为表达式
如果您像这样设计您的应用程序,您可以轻松地测试您的规范(实际上是您的表达)
答案 1 :(得分:1)
我不确定测试表达式是个好主意。但如果你愿意,你可以试试。我对这种要求至少有一个想法。
将需要提供模拟而不是您的存储库,您可以使用任何您想要的库。以Moq或NSubstitute为例。
然后,您应该在Expression<Func<Domain.Person, bool>>
调用时将SingleOrDefaultAsync
对象传递到您的存储库。对于大多数嘲弄的库来说,这应该是非常简单的。
最后,你需要将你的表达式编译成Func<Domain.Person, bool>
并断言它为true
对象返回Domain.Person
预期Id
和false
} 除此以外。
一个小快照来说明,我假设只有一个参数,存储库对象上只有一个调用,Domain.Person.Id
有公共设置器。
var repository = Substitute.For<IRepository>();
var service = new Service(repository);
var person = new Domain.Person { Id = 42 };
await service.ArchiveAsync(person);
var call = repository.ReceivedCalls().First();
var arg = call.GetArguments().First();
var expr = (Expression<Func<Domain.Person, bool>>)arg;
var func = expr.Compile();
Assert.True(func(person));
Assert.False(func(new Domain.Person {Id = 1}));