如何对传递到存储库层的表达式进行单元测试

时间:2018-05-18 14:06:05

标签: c# unit-testing lambda repository

我有一个服务层,它调用存储库层来获取数据,然后对返回对象进行操作。我想测试发送到存储库的表达式" 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方法的表达式。

思想?

2 个答案:

答案 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)

我不确定测试表达式是个好主意。但如果你愿意,你可以试试。我对这种要求至少有一个想法。

将需要提供模拟而不是您的存储库,您可以使用任何您想要的库。以MoqNSubstitute为例。

然后,您应该在Expression<Func<Domain.Person, bool>>调用时将SingleOrDefaultAsync对象传递到您的存储库。对于大多数嘲弄的库来说,这应该是非常简单的。

最后,你需要将你的表达式编译成Func<Domain.Person, bool>并断言它为true对象返回Domain.Person预期Idfalse } 除此以外。

一个小快照来说明,我假设只有一个参数,存储库对象上只有一个调用,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}));