回答你的直接问题
对于你提出的具体问题,我建议两点:
看一眼contextx.Client.ToArray()
并查看该集合中实际有多少成员。可能是Client
集合实际上是空的,在这种情况下你确实会得到 null。或者,Client 集合中的第一个元素可能具有空值EMail
.
如果您致电,行为会如何改变contextx.SaveChanges()
在查询之前Client
DbContext 上的集合?我很好奇是否打电话SaveChanges
将导致新插入的值存在于集合中。这确实不是必需的,但是 Effort 和DbContext
.
EDIT: SaveChanges()
事实证明这就是答案。
一般测试建议
由于您用“单元测试”标签标记了这个问题,因此我将根据我作为单元测试从业者和教练的十年经验提供一些通用的单元测试建议。Unit测试是关于单独测试应用程序的各个小部分。通常,这意味着单元测试一次仅与几个类交互。这也意味着单元测试不应依赖于外部库或依赖项(例如数据库)。相反,一个一体化测试同时测试系统的多个部分,并且可能对数据库等事物具有外部依赖性。
虽然这看起来像是对术语的争论,但这些术语对于将测试的实际意图传达给团队的其他成员非常重要。
在这种情况下,要么您确实想要对恰好依赖于 DbContext 的某些功能进行单元测试,要么您正在尝试测试数据访问层。如果您尝试编写直接依赖于 DbContext 的隔离单元测试,那么您需要打破对 DbContext 的依赖。我将在下面解释这一点打破对 DbContext 的依赖以下。否则,您实际上是在尝试集成测试 DbContext ,包括实体的映射方式。在这种情况下,我总是发现最好隔离这些测试并使用真实的(本地)数据库。您可能希望使用与生产中使用的数据库相同的本地安装数据库。通常,SqlExpress 工作得很好。将您的测试指向测试可能完全垃圾的数据库实例。让您的测试在运行每个测试之前删除任何现有数据。然后,他们可以设置所需的任何数据,而不必担心现有数据会发生冲突。
打破对 DbContext 的依赖
那么,当您的业务逻辑依赖于访问时,如何编写好的单元测试DbContext
? 你不知道。
在我使用实体框架进行数据持久化的应用程序中,我确保访问DbContext
包含在单独的数据访问项目中。通常,我将创建实现存储库模式的类,并且允许这些类依赖于DbContext
。所以,在这种情况下,我会创建一个ClientRepository
实现了一个IClientRepository
界面。界面看起来像这样:
public interface IClientRepository {
Client GetClientByEMail(string email);
}
然后,任何需要访问该方法的类都可以使用基本的存根/模拟/其他内容进行单元测试。无需担心嘲笑DbContext
。您的数据访问层已包含在内,您可以使用真实的数据库对其进行彻底测试。有关如何测试数据访问层的一些建议,请参阅上文。
作为一个额外的好处,该接口的实现定义了查找Client
在一个统一的地方通过电子邮件地址。这IClientRepository
界面允许您快速回答这个问题:“我们如何查询Client
我们系统中的实体?”
依赖于DbContext
与允许域类依赖连接字符串并在各处使用 ADO.Net 代码的测试问题的规模大致相同。这意味着您必须创建一个包含真实数据的真实数据存储(即使使用假数据库)。但是,如果您拥有对DbContext
在特定的数据访问程序集中,您会发现单元测试更容易编写。
就项目组织而言,我通常只允许我的数据访问项目引用实体框架。我将有一个单独的核心项目,在其中定义实体。我还将在核心项目中定义数据访问接口。然后,将具体的接口实现放入数据访问项目中。然后,解决方案中的大多数项目都可以简单地依赖于 Core 项目,只有顶级可执行文件或 Web 项目真正需要依赖于数据访问项目。