C# 替换IDBSet/IQueryable的任何()调用

C# 替换IDBSet/IQueryable的任何()调用,c#,linq,expression,iqueryable,nsubstitute,C#,Linq,Expression,Iqueryable,Nsubstitute,我试图用NSubstitute替换IDBSet的调用Any(),但测试失败,出现ArgumentNullException 测试名称:TestMethod1测试 全名:Clientmanagement.Tests.UnitTest1.TestMethod1 试验 来源:c:\develope\Clientmanagement\Clientmanagement.Tests\UnitTest1.cs :第12行测试结果:失败测试持续时间:0:00:00.3701927 结果消息:测试方法 Clien

我试图用NSubstitute替换
IDBSet
的调用
Any()
,但测试失败,出现
ArgumentNullException

测试名称:TestMethod1测试 全名:Clientmanagement.Tests.UnitTest1.TestMethod1 试验 来源:c:\develope\Clientmanagement\Clientmanagement.Tests\UnitTest1.cs :第12行测试结果:失败测试持续时间:0:00:00.3701927

结果消息:测试方法 Clientmanagement.Tests.UnitTest1.TestMethod1 异常:System.ArgumentNullException:值不能为null。 参数名称:参数结果堆栈跟踪:在 System.Linq.Expressions.Expression.RequiresCanRead(表达式 表达式,字符串参数(名称)位于 System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase 方法,表达式类型nodeKind,表达式arg,参数info pi)
位于System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase 方法,表达式类型nodeKind,只读集合
1和参数)
在System.Linq.Expressions.Expression.Call(表达式实例, MethodInfo方法,IEnumerable
1个参数)位于 System.Linq.Expressions.Expression.Call(表达式实例, MethodInfo方法,表达式[]参数)位于 System.Linq.Queryable.Any[TSource](IQueryable
1源代码,表达式
谓词)at
中的Clientmanagement.Tests.UnitTest1.TestMethod1()
c:\develope\Clientmanagement\Clientmanagement.Tests\UnitTest1.cs:line
十九,

下面是我的测试方法

public void EnsureThatIdentifierIsUnique() {
  IClientContext context = Substitute.For<IClientContext>();

  IDbSet<Client> clients = Substitute.For<IDbSet<Client>>();

  context.Clients.Returns(clients);

  clients.Any(p=>p.Identifier == "Test").Returns(true);  // this line throws the exception

  ClientService service = new ClientService(context);

  service.CreateClient("Test");
}
public void incurethattidentifierisunique(){
IClientContext上下文=替换.For();
IDbSet clients=替换.For();
context.Clients.Returns(客户);
clients.Any(p=>p.Identifier==“Test”)。返回(true);//此行抛出异常
ClientService=新的ClientService(上下文);
服务。CreateClient(“测试”);
}
现在我的问题是,是否可以用NSubstitute替换
IQueryable
的方法?我的测试方法设置是否错误

现在我的问题是,是否可以用NSubstitute替代IQueryable的方法

Any
不是
IQueryable
上的方法。它是一个扩展方法-一个静态方法,被调用时就像它是一个实例方法一样。因此,除非NSubstitute能够以某种方式模拟静态方法(就像这样),否则您将遇到问题

一个真正智能的面向LINQ的模拟系统本质上可以向
Queryable
提供虚假信息,并在生产代码提供类似的表达式树时对它们做出响应,但这将是非常脆弱的。如果可能的话,最好使用内存中的数据库

一般来说,如果另一个调用序列是等效的,则不应该依赖生产代码来生成精确的调用序列。例如,将生产代码编写为

clients.Where(p=>p.Identifier == "Test").Any()
它的可读性不高,但基本上相当于使用谓词调用
Any
。您的测试应该能够理解生产代码实现了什么,而不是实现它所需的确切步骤

现在我的问题是,是否可以用NSubstitute替代IQueryable的方法

Any
不是
IQueryable
上的方法。它是一个扩展方法-一个静态方法,被调用时就像它是一个实例方法一样。因此,除非NSubstitute能够以某种方式模拟静态方法(就像这样),否则您将遇到问题

一个真正智能的面向LINQ的模拟系统本质上可以向
Queryable
提供虚假信息,并在生产代码提供类似的表达式树时对它们做出响应,但这将是非常脆弱的。如果可能的话,最好使用内存中的数据库

一般来说,如果另一个调用序列是等效的,则不应该依赖生产代码来生成精确的调用序列。例如,将生产代码编写为

clients.Where(p=>p.Identifier == "Test").Any()

它的可读性不高,但基本上相当于使用谓词调用
Any
。您的测试应该能够实现生产代码所实现的功能,而不是实现它所需的确切步骤。

模拟表达式树很难,一些框架完全不支持它(我在看您,
Moq
)。模仿静态助手/扩展方法更难(现在我来看看你,
Dapper
;)。我不完全确定EF现在在这个领域的进展如何,但您所描述的是为什么——当我使用NHibernate时——我将数据库交换到内存中的SQLite DB进行单元测试,在这里我可以设置自定义数据。模拟表达式树很难,一些框架完全不支持它(我在看您,
Moq
)。模仿静态助手/扩展方法更难(现在我来看看你,
Dapper
;)。我不完全确定EF现在在这个领域的进展如何,但您所描述的是为什么-当我使用NHibernate时-我将数据库交换到内存中的SQLite DB进行单元测试,在这里我可以设置自定义数据。好的,谢谢您的回答。现在我看到了替换呼叫的问题。但是我应该如何正确设置测试呢。我应该为
IDbSet
定义一个额外的接口,使用
ExistsIdentifier(string)
方法来封装linq查询,并更改我的测试方法来处理新接口,并替换对
ExistSidentier(string)
的调用吗?@Jehof:这是一个选项,或者你可以使用内存数据库,正如我提到的,我将看一看用于单元测试的内存数据库。谢谢你。好的,谢谢你的回答。现在我看到了替换呼叫的问题。但是我应该如何正确设置测试呢。我是否应该使用
ExistsIdentifier(string)
方法为
IDbSet
定义一个附加接口来封装linq-q