问题描述
我试图对已经创建的类进行单元测试,但是大多数类都与数据库打交道.我已经获得了与数据库无关的类,可以在本地进行很好的测试,但是当涉及到数据库(尤其是远程数据库)时,我感到很困惑.该指南显示了使用PDO访问似乎已转储到XML文件的本地数据库,因此对我来说几乎没有用,因为我的数据库位于Amazon云中,并且使用pg_ *函数连接到Postgres数据库.
I'm trying to unit test the classes I've created but the majority of the classes deal with the database. I've gotten non-database related classes to be test just fine locally, but I'm stumped when it comes to work with a database, especially remotely. The guide shows using PDO to access a local database that seems to be dumped to an XML file, so it's of little use to me since my database is in the Amazon cloud and using pg_* functions to connect to a Postgres database.
有没有类似情况的好例子,或者任何人都可以提供帮助吗?我不知道我应该在文件中具有数据库的本地版本还是连接到远程服务器.如果必须连接,该怎么做才能使其正常工作?
Are there any good examples of a similar situation or can anyone offer any help? I don't know if I should have a local version of my DB in a file or connect to the remote server. If I have to connect, what do I have to do to make it work?
结论
我和项目架构师进行了调查,我们确定实施ORM最好,因为没有对数据库的抽象.在此之前,数据库测试将保持不变.安装到位后,我相信PHPUnit手册会更有意义.
Conclusion
The project architect and I did an investigation and we determined it would be best to implement an ORM, since there was no abstraction to the database. Until then, database testing will be on hold. Once in place, I'm sure the PHPUnit manual will make much more sense.
推荐答案
简短的答案是在PHPUnit手册上阅读有关数据库测试的高级手册条目.
关于单元测试的第一件事要记住,它需要与其他所有组件进行 隔离 .通常,使用控制反转(IoC)技术(例如依赖注入 .当您的类在构造函数方法中明确要求其依赖性时,这是模拟 这些依赖项,以便您可以单独测试其余代码.
The first thing to remember about unit testing is that it needs to be performed in isolation from all other components. Often, this goal is simplified using inversion of control (IoC) techniques like dependency injection. When your classes explicitly ask for their dependencies in the constructor methods it's a simple operation to mock those dependencies so that you can test the remaining code in isolation.
不过,与模型交互的测试代码有些不同.通常,将模型注入需要访问它们的类中是不切实际或不明智的.您的模型通常是笨拙"的数据结构,仅显示有限的功能或没有功能.结果,就可注入性而言,在可测试性方面实例化模型通常是可以接受的.不幸的是,这使测试数据库代码变得困难,因为如PHPUnit文档所述:
Testing code that interacts with models is a bit different, though. Usually it's not practical or advisable to inject your models into the class in which you need to access them. Your models are generally "dumb" data structures that expose limited or no capabilities. As a result, it's generally acceptable (in terms of testability) to instantiate your models on the fly inside your otherwise-injected classes. Unfortunately, this makes testing database code difficult because, as the PHPUnit documentation notes:
那么,如果不直接注入模型,如何隔离和测试与数据库交互的代码?最简单的方法是利用测试治具 .
So how do you isolate and test code that interacts with the database if the models aren't directly injected? The simplest way to do this is to utilize test fixtures.
由于您肯定已经在使用PDO
或基于PDO
构建的ORM库(对吗?),设置固定装置就像为基本的SQLite数据库或XML文件填充数据以容纳您的测试用例,并在测试与数据库交互的代码时使用该特殊的数据库连接一样简单.您可以在PHPUnit引导文件中指定此连接,但在语义上更适合设置 PHPUnit数据库TestCase .
Since you're definitely already using PDO
or an ORM library that builds on PDO
(right?),setting up the fixtures is as simple as seeding a basic SQLite database or XML file with data to accommodate your test cases and using that special database connection when you test the code that interacts with the database. You could specify this connection in your PHPUnit bootstrap file, but it's probably more semantically appropriate to setup a PHPUnit Database TestCase.
用于测试数据库代码的公认的最佳实践步骤(有关DB测试的PHPUnit文档中也回响了这些步骤):
The generally accepted best practice steps for testing DB code (these are also echoed in the PHPUnit documentation on DB testing):
- 设置灯具
- 被测运动系统
- 验证结果
- 拆卸
因此,总而言之,您需要做的就是创建一个虚拟"数据库设备,并使您的代码与该已知数据进行交互,而不是与您在生产中使用的实际数据库进行交互.这种方法使您能够成功隔离正在测试的代码,因为它处理的是已知数据,这意味着您可以对数据库操作的结果进行特定/可测试的断言.
So, to summarize, all you need to do is create a "dummy" database fixture and have your code interact with that known data instead of an actual database you would use in production. This method allows you to successfully isolate the code under test because it deals with known data, and this means you can make specific/testable assertions about the results of your database operations.
更新
只是因为这对于在代码中要执行 not 的操作非常有用,所以如果要提高可测试性,我要添加一个链接到Misko Hevery的如何编写不可测试的3v1L代码.它并不特别涉及数据库测试,但是仍然很有帮助.测试愉快!
Just because it's an extraordinarily useful guide for what not to do in your code if you want to promote testability, I'm adding a link to Misko Hevery's How to Write 3v1L, Untestable Code. It's not involved with database testing in particular, but it's helpful nevertheless. Happy testing!
更新2
我想回应有关推迟模型测试的评论,因为现有代码库未实现PDO
用于数据库访问:
I wanted to respond to the comment about putting off model testing because the existing code base doesn't implement PDO
for database access:
您的模型不必使用PDO来实现PHPUnit的DbUnit扩展.
如果使用PDO,将使您的生活更加轻松,但并非必须如此.举例来说,您已经使用PHP的内置pg_*
PostgreSQL函数构建了应用程序. PHPUnit仍然允许您指定固定装置,并且仍可以为每个测试重建它们-您只需在执行测试时将连接指向DbUnit扩展用于其固定装置的相同资源即可.
It will make your life a bit easier if you use PDO, but you aren't required to do so. Say, for example, you've built your application with PHP's built-in pg_*
PostgreSQL functions. PHPUnit still allows you to specify fixtures and it can still rebuild them for each test -- you would simply need to point your connection when performing tests to the same resource the DbUnit extension uses for its fixture.
这篇关于PHPUnit:如何在远程Postgres服务器上测试数据库交互?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!