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