努力-伪造数据库时FirstOrDefault返回null [英] Effort- FirstOrDefault returns null when Faking Database

查看:81
本文介绍了努力-伪造数据库时FirstOrDefault返回null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的项目创建一些单元测试,经过大量挖掘之后,我发现很努力,这个主意很棒,它模拟数据库而不是处理伪造的DBContext,顺便说一下,这真的很难得到使用复杂的架构就可以了.

I'm trying to create some unit tests for my project, after much digging around I found Effort, the idea is great, it mocks the database instead of the dealing with faking the DBContext which by the way is really hard to get it right when using a complex schema.

但是,在我将用户的电子邮件特别添加到Effort创建的内存数据库后,我试图获取该用户的电子邮件,这是代码

However I'm trying to get the Email of a user after I specifically added it to the in-memory database create by Effort, here is the code

MyContext contextx = new MyContext(Effort.DbConnectionFactory.CreateTransient());

var client = new Client
{
    ClientId = 2,
    PersonId = 3,
    Person = new Person
    {
        PersonId = 3,
        EMail = "xxxxx@gmail.com"
    }
};
contextx.Client.Add(client); //<-- client got added, I checked it and is there

var email = contextx.Client.Select(c => c.Person.EMail).FirstOrDefault(); 

在上面的最后一行中,我无法使其返回电子邮件xxxx@gmail.com,而是始终返回null.

In the last line above I can't make it to return the email xxxx@gmail.com instead it always returns null.

有什么想法吗?

推荐答案

回答您的直接问题

对于您提出的具体问题,我建议两件事:

Answering Your Direct Question

For the specific question you asked, I would suggest two things:

  1. 看看contextx.Client.ToArray(),看看您实际上在该集合中有多少个成员. Client集合实际上可能是空的,在这种情况下,您确实会得到null.或者,可能是Client集合中的第一个元素的EMail值为空.

  1. Take a look at contextx.Client.ToArray() and see how many members you really have in that collection. It could be that the Client collection is actually empty, in which case you'll indeed get null. Or, it could be that the first element in the Client collection has a null value for EMail.

如果在DbContext上查询Client集合之前调用contextx.SaveChanges(),行为将如何改变?我很好奇,看看是否调用SaveChanges会导致新插入的值存在于集合中.确实不需要这样做,但是Effort和DbContext之间可能会有一些奇怪的相互作用.

How does the behavior change if you call contextx.SaveChanges() before querying the Client collection on the DbContext? I'm curious to see if calling SaveChanges will cause the newly inserted value to exist in the collection. This really shouldn't be required, but there might be some strange interaction between Effort and the DbContext.

SaveChanges()原来是答案.

由于您使用单元测试"标签来标记此问题,因此,根据我作为单元测试从业人员和教练的十年经验,我将提供一些常规的单元测试建议. Unit 测试是关于单独测试应用程序的各个小部分.通常,这意味着单元测试一次只能与几个类交互.这也意味着单元测试不应依赖于外部库或依赖项(例如数据库).相反, integration 测试会一次练习系统的更多部分,并且可能对数据库等事物具有外部依赖性.

Since you tabbed this question with the "unit-testing" tag, I'll offer some general unit testing advice based on my ten years spent as a unit testing practitioner and coach. Unit testing is about testing various small parts of your application in isolation. Typically this means that unit tests only interact with a few classes at once. This also means that unit tests should not depend on external libraries or dependencies (such as the database). Conversely, an integration test exercises more parts of the system at once and may have external dependencies on things like databases.

尽管这似乎是对术语的一种质疑,但这些术语对于将测试的实际意图传达给团队的其他成员很重要.

While this may seem like a quibble over terminology, the terms are important for conveying the actual intent of your tests to other members of your team.

在这种情况下,您要么真的是想对依赖于DbContext的某些功能进行单元测试,要么就是尝试测试数据访问层.如果要编写直接依赖于DbContext的对象的隔离单元测试,则需要打破对DbContext的依赖.我将在下面的打破对DbContext的依赖性中对此进行解释.否则,您实际上是在尝试集成测试DbContext,包括如何映射实体.在这种情况下,我总是发现最好隔离这些测试并使用真实的(本地)数据库.您可能想要使用与生产中使用的相同种类的本地安装数据库.通常,SqlExpress可以正常工作.将您的测试指向数据库实例,这些实例可以完全破坏这些测试.让您的测试在运行每个测试之前删除所有现有数据.然后,他们可以设置所需的任何数据,而不必担心现有数据会发生冲突.

In this case, either you are really wanting to unit test some piece of functionality that happens to depend on DbContext, or you are attempting to test your data access layer. If you're trying to write an isolated unit test of something that depends on the DbContext directly, then you need to break the dependency on the DbContext. I'll explain this below in Breaking the Dependency on DbContext below. Otherwise, you're really trying to integration test your DbContext including how your entities are mapped. In this case, I've always found it best to isolate these tests and use a real (local) database. You probably want to use a locally installed database of the same variety you're using in production. Often, SqlExpress works just fine. Point your tests at an instance of the database that the tests can completely trash. Let your tests remove any existing data before running each test. Then, they can setup whatever data they need without concern that existing data will conflict.

那么,当您的业务逻辑依赖于访问DbContext时,如何编写良好的单元测试? 您没有.

So then, how do you write good unit tests when your business logic depends on accessing DbContext? You don't.

在使用Entity Framework进行数据持久化的应用程序中,我确保对DbContext的访问包含在单独的数据访问项目中.通常,我将创建实现存储库模式的类,并允许这些类依赖于DbContext.因此,在这种情况下,我将创建一个实现IClientRepository接口的ClientRepository.界面看起来像这样:

In my applications that use Entity Framework for data persistence, I make sure access to the DbContext is contained within a separate data access project. Typically, I will create classes that implement the Repository pattern and those classes are allowed to take a dependency on DbContext. So, in this case, I would create a ClientRepository that implements an IClientRepository interface. The interface would look something like this:

public interface IClientRepository {

    Client GetClientByEMail(string email);

}

然后,任何需要访问该方法的类都可以使用基本存根/mock/进行任何单元测试.不必担心模拟DbContext.您的数据访问层已包含在内,您可以使用真实的数据库进行全面测试.有关如何测试数据访问层的一些建议,请参见上文.

Then, any classes that need access to the method can be unit tested using a basic stub / mock / whatever. Nothing has to worry about mocking out DbContext. Your data access layer is contained, and you can test it thoroughly using a real database. For some suggestions on how to test your data access layer, see above.

另一个好处是,此接口的实现定义了在单个统一的位置中通过电子邮件地址查找Client的含义. IClientRepository界面使您可以快速回答以下问题:我们如何在系统中查询Client实体?"

As an added benefit, the implementation of this interface defines what it means to find a Client by email address in a single, unified place. The IClientRepository interface allows you to quickly answer the question, "How do we query for Client entities in our system?"

DbContext进行依赖与测试问题的规模大致相同,即允许域类对连接字符串具有依赖关系并且到处都具有ADO.Net代码.这意味着您必须创建一个包含真实数据的真实数据存储(即使使用伪造的db).但是,如果将对DbContext的访问包含在特定的数据访问程序集中,则会发现您的单元测试更容易编写.

Taking a dependency on DbContext is roughly the same scale of a testing problem as allowing domain classes to take a dependency on the connection string and having ADO.Net code everywhere. It means that you have to create a real data store (even with a fake db) with real data in it. But, if you contain your access to the DbContext within a specific data access assembly, you'll find that your unit tests are much easier to write.

就项目组织而言,我通常只允许我的数据访问项目引用Entity Framework.我将有一个单独的Core项目,在其中定义实体.我还将在Core项目中定义数据访问接口.然后,将具体的接口实现放入数据访问项目中.然后,解决方案中的大多数项目都可以简单地依赖Core项目,而只有顶级可执行文件或Web项目才真正需要依赖数据访问项目.

As far as project organization, I typically only allow my data access project to take a reference to Entity Framework. I'll have a separate Core project in which I define the entities. I'll also define the data access interfaces in the Core project. Then, the concrete interface implementations get put into the data access project. Most of the projects in your solution can then simply take a dependency on the Core project, and only the top level executable or web project really needs to depend on the data access project.

这篇关于努力-伪造数据库时FirstOrDefault返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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