Moq'ing 方法,其中 Expression<Func<T,bool>>作为参数传入 [英] Moq'ing methods where Expression<Func<T, bool>> are passed in as parameters

查看:18
本文介绍了Moq'ing 方法,其中 Expression<Func<T,bool>>作为参数传入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对单元测试和模拟非常陌生!我正在尝试编写一些单元测试,涵盖与数据存储交互的一些代码.数据访问由IRepository封装:

I'm very new to unit testing and mocking! I'm trying to write some unit tests that covers some code that interacts with a data store. Data access is encapsulated by IRepository:

interface IRepository<T> {
    ....
    IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);
    ....
}

我尝试使用 IRepository 的具体 IoC 实现来测试的代码如下所示:

The code that I'm trying to test, utilising a concrete IoC'd implementation of IRepository looks like this:

public class SignupLogic {
    private Repository<Company> repo = new Repository<Company>();

    public void AddNewCompany(Company toAdd) {
        Company existingCompany = this.repo.FindBy(c => c.Name == toAdd.Name).FirstOrDefault();

        if(existingCompany != null) {
            throw new ArgumentException("Company already exists");
        }

        repo.Add(Company);
        repo.Save();
    }
}

为了测试 SignupLogic.AddNewCompany() 本身的逻辑,而不是逻辑和具体的 Repository,我模拟了 IRepository 并将其传递给 SignupLogic.模拟的 Repository 看起来像这样:

So that I'm testing the logic of SignupLogic.AddNewCompany() itself, rather than the logic and the concrete Repository, I'm mocking up IRepository and passing it into SignupLogic. The mocked up Repository looks like this:

Mock<Repository> repoMock = new Mock<Repository>();
repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc")....

返回一个内存中的 IEnumberable,其中包含一个名称设置为Company Inc"的 Company 对象.调用 SignupLogic.AddNewCompany 的单元测试设置了一个具有重复详细信息的公司并尝试将其传入,并且我断言抛出了带有消息公司已经存在"的 ArgumentException.这个测试没有通过.

which returns an in-memory IEnumberable containing a Company object with name set to "Company Inc". The unit test that calls SignupLogic.AddNewCompany sets up a company with duplicate details and trys to pass that in, and I assert that an ArgumentException is thrown with the message "Company already exists". This test isn't passing.

通过单元测试和 AddNewCompany() 在运行时进行调试,将出现 existingCompany 始终为空.无奈之下,我发现如果我更新 SignupLogic.AddNewCompany() 以便 FindBy 的调用看起来像这样:

Debugging through the unit test and AddNewCompany() as it runs, it would appear that existingCompany is always null. In desperation, I've found that if I update SignupLogic.AddNewCompany() so that the call to FindBy looks like this:

Company existingCompany = this.repo.FindBy(c => c.Name == "Company Inc").FirstOrDefault();

测试通过,这表明 Moq 只响应与我在测试装置中设置的完全相同的代码.显然,这在测试 SignupLogic.AddNewCompany 拒绝任何重复公司时并不是特别有用.

the test passes, which suggests to me that Moq is only responding to code that is exactly the same as I've setup in my test fixture. Obviously that's not especially useful in testing that any duplicate company is rejected by SignupLogic.AddNewCompany.

我已经尝试将 moq.FindBy(...) 设置为使用Is.ItAny",但这也不会导致测试通过.

I've tried setting up moq.FindBy(...) to use "Is.ItAny", but that doesn't cause the test to pass either.

从我正在阅读的所有内容来看,我正在尝试的表达式测试似乎无法在此处使用 Moq.是否可以?请帮忙!

From everything I'm reading, it would appear that testing Expressions as I'm trying to isn't actually do-able with Moq here. Is it possible? Please help!

推荐答案

只有具有完全相同结构(和文字值)的 Expression 才会匹配可能是正确的.我建议你使用 Returns() 的重载,它允许你使用调用模拟的参数:

It is probably correct that only an Expression with the exactly same structure (and literal values) will match. I suggest that you use the overload of Returns() that lets you use the parameters the mock is called with:

repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())
        .Returns((Expression<Func<Company, bool>> predicate) => ...);

... 中,您可以使用 predicate 返回匹配的公司(如果匹配的公司不是您所期望的,甚至可能抛出异常).不是很漂亮,但我认为它会起作用.

In ..., you can use predicate to return the matching companies (and maybe even throw an exception if the matching companies isn't what you expected). Not very pretty, but I think it will work.

这篇关于Moq'ing 方法,其中 Expression&lt;Func&lt;T,bool&gt;&gt;作为参数传入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆