我正在测试一个工厂,它可以简单地检索新闻系统的所有“帖子”。我会将示例简化为尽可能简单的内容:
$newsFactory->getAllNews();
表格如下所示:
+---------+---------------------+-------------+
| news_id | news_publishedDate | news_active |
+---------+---------------------+-------------+
| 1 | 2010-03-22 13:20:22 | 1 |
| 2 | 2010-03-23 13:20:22 | 1 |
| 14 | 2010-03-23 13:20:22 | 0 |
| 15 | 2010-03-23 13:20:22 | 1 |
+---------+---------------------+-------------+
我想测试这种行为;现在,我们只关注第一个:
- 确保查询仅返回 news_active=1
- 确保查询将返回按 news_publishedDate 从最新到较旧排序的元素。
因此,我制作了一个 dbData.xml
数据集,其中包含我认为良好的测试数据:
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="news">
<column>news_id</column>
<column>news_publishedDate</column>
<column>news_active</column>
<row>
<value>1</value>
<value>2010-03-20 08:55:05</value>
<value>1</value>
</row>
<row>
<value>2</value>
<value>2010-03-20 08:55:05</value>
<value>0</value>
</row>
<row>
<value>3</value>
<value>2011-03-20 08:55:05</value>
<value>1</value>
</row>
</table>
</dataset>
好的,让我们检查第一个测试(不从 XML 数据集中返回 news_id
#2)
我必须扩展 PHPUnit_Extensions_Database_TestCase
类来创建我的 NewsFactoryTest 类:
<?php
require_once 'PHPUnit/Extensions/Database/TestCase.php';
class NewsFactoryTest extends PHPUnit_Extensions_Database_TestCase
{
protected $db;
protected function getConnection()
{
$this->db = new PDO('mysql:host=localhost;dbname=testdb', 'root', '');
return $this->createDefaultDBConnection($this->db, 'testdb');
}
protected function getDataSet()
{
return $this->createXMLDataSet(dir(__FILE__) . DIRECTORY_SEPARATOR . 'dbData.xml');
}
public function testGetNewsById()
{
$newsFactory = new NewsFactory($this->db);
$news = $newsFactory->getNewsById();
// ???
$this->assertEquals(2, count($news), "Should return only 2 results");
}
}
我的主要问题是如何设置该测试?
详细来说,我尝试理解:
- 我应该创建一个 testdb 数据库还是全是模拟/虚拟的?
- 我见过很多使用
sqlite::memory:
的示例,使用 sqlite 测试基于 MySQL 的查询是个好主意吗?我可以使用mysql::memory:
代替吗? - 如果是真实的数据库,如何在每次测试运行之前恢复数据库中
dbData.xml
中的所有数据?
- 我见过很多使用
- 我应该在哪里调用
getConnection()
和getDataSet()
?
感谢您阅读并分享您的知识!
最佳答案
我在我们的项目中设置了数据库测试,以下是一些对我们有用的答案和经验教训:
Should I create a testdb database or is that all emulated/virtual ?
我一开始就问了同样的问题,我们都知道它确实是一个正在运行的真正的数据库。
I've seen many examples using sqlite::memory: , is it a good idea to test MySQL based query with sqlite ? Can I use mysql::memory: instead ?
我尝试使用 sqlite 来提高性能,但发现 SQL 的差异很大,无法在我们现有的代码中随处使用。我能够对大多数表使用 MySQL MEMORY 引擎(对于某些表(例如 BLOB 列)是不可能的)。
If it's a real DB, how do I restore all the data from dbData.xml in the DB before each test run ?
我编写了一个脚本,从我们的远程测试服务器调用架构及其所有表的 mysqldump,将它们插入本地服务器,并将所有可能的表引擎转换为 MEMORY。这确实需要时间,但由于模式在测试之间不会改变,因此它只在最顶层的 TestSuite 上运行一次,或者根据开发人员的需要在本地系统上单独运行。
数据集在每次测试开始时加载,并且由于表已经存在并且在内存中,因此测试之间的插入和截断速度很快。
block 引用>Where am I supposed to call getConnection() and getDataSet() ?
我们已经有一个扩展 TestCase 的帮助程序类,因此我无法使用 PHPUnit_Extensions_Database_TestCase。我将设置函数添加到该帮助程序类中,并且从未调用或必须实现 getDataSet()。我确实使用 getConnection() 从断言函数中修改的数据创建数据集。
/** * @param PHPUnit_Extensions_Database_DataSet_IDataSet $expected_data_fixture * @param string|array $tables */ protected function assertDataFixturesEqual($expected_data_fixture, $tables){ if(!is_array($tables)){ $tables = array($tables); } PHPUnit_Extensions_Database_TestCase::assertDataSetsEqual($expected_data_fixture, $this->DbTester->getConnection()->createDataSet($tables)); }
编辑: 我发现我使用的一些资源书签,因为 PHPUnit 文档有点缺乏:
http://www.ds-o.com/archives/63-PHPUnit-Database-Extension-DBUnit-Port.html
http://www.ds-o.com/archives/64-Adding-Database-Tests-to-Existing-PHPUnit-Test-Cases.html
关于database - PHPUnit - 断言查询从数据库返回正确的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5411489/