单元测试和数据库
这个关于单元测试的问题 引发了另一件困扰我的事情。我反复研究了在访问数据库时进行单元测试的三种方法。
- 创建模拟对象并将其插入。这样做的优点是不需要数据库,但它很耗时,而且我不确定我能获得多少投资回报。我已经了解了一些 IOC 和起订量,但看起来仍然很痛苦。
- 创建安装和拆卸数据库脚本来创建已知案例并对其进行测试。同样,这可能会耗费大量时间,但大多数时候仍然比模拟对象更容易创建。假设其他工作人员的本地主机上有 SQL 服务器,他们仍然可以运行它。
- 手动检查开发数据库并修改单元测试。密集的手动工作,但如果我有一个不改变的“测试集”,它似乎工作正常。至少在我的机器上:-)。
我知道选项 1 是进行单元测试的“正确”方法,但在这三个选项中,这可能是我使用最少的选项(尽管最新的项目已经与 IOC 合作,所以这扇门向我敞开)。我意识到这很大程度上取决于正在嘲笑的内容和正在测试的内容,但我在这里错过了什么?
如果上下文有帮助的话,我在一家 C# 商店中编写内部应用程序,只有几个开发人员。
This question about unit tests sparked another thing that's been bothering me. I've gone back and forth on three ways to do unit tests when hitting a database.
- Create mock objects and plug them in. This has the advantage of not needing a database, but it's time consuming and I'm not sure how much return on investment I'm getting. I've been getting into IOC and moq a little bit, but it still seems painful.
- Create a setup and teardown database scripts to create known cases, and test for those. Again, can be time intensive, but still easier to create than mock objects most of the time. And other people at work can still run it assuming they have SQL server on their localhost.
- Manually check the dev database and modify unit tests. Intensively manual work, but if I have a "test set" that doesn't change, it seems to work OK. On my machine, at least :-).
I know option 1 is the "proper" way to do unit tests, but of the three, that's probably the option I've used the least (although the latest projects have been with IOC, so that door is open to me). I realize a lot of it depends on what exactly is being mocked and what is being tested, but what am I missing here?
If context helps, I'm in a C# shop, writing in-house applications, only a few developers.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您有一个仅公开少数
IQueryable
方法的数据访问层,那么第一个应该不会那么难。有一个很好的技巧可以用于伪造数据:只需将实体对象存储在List
中并使用AsQueryable
。我发现这比数据部分的起订量更容易。关于 IOC,我的立场是它目前被过度使用(请注意,我的观点代表了这方面的少数程序员)。您可以在测试过程中使用 Moles 之类的工具进行模拟,而不必滥用你的程序的设计。除非设计确实需要,否则我不会使用 IOC。
The first one shouldn't be that hard if you've got a Data Access Layer that exposes just a handful of
IQueryable<T>
methods. There's a nice trick you can use for fake data: just store the entity objects in aList<T>
and useAsQueryable
. I find this easier than moq for the data parts.Regarding IOC, I take the position that it's currently overused (be aware that my opinion represents the minority of programmers in this regard). You can use a tool like Moles during testing to mock without having to abuse your program's design. I don't use IOC unless the design actually calls for it.
我肯定会继续使用真正的单元测试(选项 1)。我喜欢斯蒂芬对此的建议。
您可能还会发现与实际数据库的集成测试(选项 2)也必要(选项 2)。为什么?因为真正的单元测试并未涵盖您需要测试的部分内容(O/R 映射、与实际数据库模式的兼容性等)。
至于设置和拆卸逻辑,继承它通常就足够了(使用 .NET、NUnit 和 SqlServer 作为数据库):
简单易行。
I would definitely continue to use true unit tests (option 1). I like Stephen's advice for this.
You may also find integration tests with an actual database (option 2) necessary to use as well (option 2). Why? Because part of what you need to test (O/R mapping, compatability with the actual DB schema, etc.) are not covered by true unit tests.
As for setup and teardown logic, inheriting from this usually suffices (using .NET, NUnit, and SqlServer for the database):
Easy as pie.
对此有一整套答案。要做的第一件事是清楚地阐明您正在测试的内容。它是一个 API 的外观,背后有一个数据库、DAO 对象、您的数据库结构吗?
做到这一点还将帮助您决定测试事物的最佳方法。据我所知,还有您列出的替代方案。也就是说,在内存数据库(例如 hsql)中启动,并针对该数据库运行类和测试。这意味着您可以在测试开始时创建数据库结构。因为它位于内存中,所以您不必担心拥有数据库服务器,它速度很快,并且您可以加载特定于测试的数据。
我经常使用模拟,虽然它们非常适合对类进行单元测试,但在某些情况下却并非如此。他们也很容易错过领先机会。与模拟一起工作的东西在集成时不起作用的情况并不罕见。原因是您正在加载带有某些期望和响应的模拟,您可能错误地从模拟所代表的事物中解释了这些期望和响应。
不要误会我的意思,我喜欢模拟并且经常使用它们。但这样做时,您绝不能假设因为某些东西经过了单元测试,所以它是正确的。它确实增加了机会,但在集成测试中实际上给你 100% 的保证。
There's a whole suite of answer to this. The first thing to do is to clearly articulate what you are testing. Is it the facade of an API that has a database behind it, DAO objects, your database structure?
Getting to this will also help you decide the best way to test things. There is also from what I can see an alternative to the ones you list. That is to start up in in memory database such as hsql and run your classes and tests against that. This means that you can create the database structure at the start of you tests. Because it's in memory you don't have to worry about having a database server, it's fast, and you can load it with data specific to your test.
I use mocks quite a bit and whilst they are great for unit testing a class, in some cases they are not. They can also miss lead quite easily. It's not uncommon for something that works with mocks, to not work when integrated. The reasonnfor this is that you are loading the mock with certain expectations and responses, which you may have wrongly intepreted from the thing that the mock represents.
Don't get me wrong, I like mocks and use them quite a bit. But in doing so you must never assume that because something is unit tested, it's correct. It does increases the chances, but on integration tests actually give you 100% assurance.
你真正测试的是什么让你觉得这很困难?
如果将业务和服务层逻辑与持久性代码解耦,那么您应该能够轻松隔离想要进行单元测试的代码,而无需使用数据库。
单元测试最重要的原则之一是解耦和隔离测试。当您清楚地了解如何做到这一点时,单元测试就很容易了。如果不这样做,单元测试就会变得困难。
What are you testing really that makes you feel that this is difficult?
If you decouple your business and service layer logic from your persistance code, you should easilly be able to isolate the code you want to unit test without having to a DB.
One of the most important principles of unit testing is to decouple and test in isolation. When you have a clear understanding of how to do that, unit testing is easy. When you don't, unit testing becomes hard.