Database PHPUnit-断言查询从数据库返回正确的数据
我正在测试一个只检索新闻系统所有“帖子”的工厂。我将把示例简化为尽可能简单的内容:Database PHPUnit-断言查询从数据库返回正确的数据,database,phpunit,Database,Phpunit,我正在测试一个只检索新闻系统所有“帖子”的工厂。我将把示例简化为尽可能简单的内容: $newsFactory->getAllNews(); 该表如下所示: +---------+---------------------+-------------+ | news_id | news_publishedDate | news_active | +---------+---------------------+-------------+ | 1 | 2010-03-22 1
$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\u active=1
- 确保查询将返回由news_publishedDate排序的元素,从最新到较旧
所以我做了一个<代码> dBata.xml < /CataDataSet,我认为是好的测试数据:
<?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>
我的主要问题是如何设置该测试
具体而言,我试图理解:
- 我应该创建一个testdb数据库,还是全部都是仿真/虚拟的?
- 我已经看到了许多使用sqlite::memory:的示例,使用sqlite测试基于MySQL的查询是一个好主意吗?我可以改用
吗mysql::memory:
- 如果它是一个真实的数据库,那么在每次测试运行之前,如何从数据库中的
恢复所有数据dbData.xml
- 我已经看到了许多使用sqlite::memory:的示例,使用sqlite测试基于MySQL的查询是一个好主意吗?我可以改用
- 我应该在哪里调用
和getConnection()
getDataSet()
感谢阅读并分享您的知识 我没有使用PHPUnit的数据库测试用例,所以我必须将我的答案限制在断言上。您可以断言ID 2不在
$news
中,也可以断言$news
中的每个对象都处于非活动状态。后者更灵活,因为在向测试数据集添加数据时,不需要更改测试
$news = $newsFactory->getNewsById();
foreach ($news as $item) {
self::assertTrue($news->isActive());
}
顺便说一句,数据集中的发布日期都是相同的。这将使测试订购变得不可能。;) 到目前为止,我了解到: 我应该创建一个testdb数据库,还是全部都是仿真/虚拟的? 它创建了一个真实的数据库,并且使用getSetUpOperation方法,它的速度非常慢,因为每次测试都会截断和重新导入表,而且即使对于少量数据,它也需要大量的硬盘。(~1秒/测试) 我见过许多使用sqlite::memory:的示例,使用sqlite测试基于MySQL的查询是个好主意吗?我可以改用mysql::memory:吗? 我还是不知道。我认为MySQL现在真的可以实现了 如果是真实的数据库,如何在每次测试运行之前从数据库中的dbData.xml恢复所有数据? 有getSetUpOperation和getTearDownOperation,它们的作用类似于setup和tearDown方法。添加此项将截断数据集中提到的表,并重新插入该xml文件的所有数据:
/**
* Executed before each
*
* @return PHPUnit_Extensions_Database_Operation_DatabaseOperation
*/
protected function getSetUpOperation()
{
return PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT();
}
我应该在哪里调用getConnection()和getDataSet()?
没有。这些是自动调用的神奇方法。在测试之前调用getConnection(有点像_构造,但我不确定顺序),当需要数据集时调用getDataSet。我认为在我的例子中,只有getSetUpOperation对数据集具有依赖性。。。因此,在后台,它在每次测试之前调用getDataSet方法来执行CLEAN_INSERT操作
此外,我发现我们需要创建表结构(数据集不处理该结构),因此我的完整的、缓慢的工作代码是:
<?php
require_once 'PHPUnit/Extensions/Database/TestCase.php';
class NewsFactoryTest extends PHPUnit_Extensions_Database_TestCase
{
/**
* Custom PDO instance required by the SUT.
*
* @var Core_Db_Driver_iConnector
*/
protected $db;
/**
* Create a connexion.
* Note: les constantes de connexion sont définit dans bootstrap.php.
*
* @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
protected function getConnection()
{
//Instanciate the connexion required by the system under test.
$this->db = new Core_Db_Driver_PDO('mysql:host=' . TEST_DB_HOST . ';dbname=' . TEST_DB_BASE, TEST_DB_USER, TEST_DB_PASS, array());
//Create a genuine PDO connexion, required for PHPUnit_Extensions_Database_TestCase.
$db = new PDO('mysql:host=' . TEST_DB_HOST . ';dbname=' . TEST_DB_BASE, TEST_DB_USER, TEST_DB_PASS);
$this->createTableSchema($db);
return $this->createDefaultDBConnection($db, TEST_DB_BASE);
}
/**
* Load the required table schemes.
*
* @param PDO $db
* @return void
*/
protected function createTableSchema(PDO $db)
{
$schemaPath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'sql_schema' . DIRECTORY_SEPARATOR;
$query = file_get_contents($schemaPath . 'news.sql');
$db->exec($query);
$query = file_get_contents($schemaPath . 'news_locale.sql');
$db->exec($query);
}
/**
* Load the dataSet in memory.
*
* @return PHPUnit_Extensions_Database_DataSet_IDataSet
*/
protected function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'newsFactory_dataSet.xml');
}
/**
* Method executed before each test
*
* @return PHPUnit_Extensions_Database_Operation_DatabaseOperation
*/
protected function getSetUpOperation()
{
//TRUNCATE the table mentionned in the dataSet, then re-insert the content of the dataset.
return PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT();
}
/**
* Method executed after each test
*
* @return PHPUnit_Extensions_Database_Operation_DatabaseOperation
*/
protected function getTearDownOperation()
{
//Do nothing ( yup, their's a code for that )
return PHPUnit_Extensions_Database_Operation_Factory::NONE();
}
/**
* @covers NewsFactory::getNewsById
*/
public function testGetNewsById()
{
$newsFactory = new NewsFactory($this->db);
$news = $newsFactory->getNewsById(999);
$this->assertFalse($news);
}
}
我在我们的项目中设置了数据库测试,以下是一些对我们有用的答案和教训:
我应该创建一个testdb数据库,还是全部都是仿真/虚拟的?
一开始我问了同样的问题,我们都知道它确实是一个真正的数据库
我见过许多使用sqlite::memory:的示例,使用sqlite测试基于MySQL的查询是个好主意吗?我可以改用mysql::memory:吗?
我试图使用sqlite来提高性能,但发现SQL的不同程度足以使我们现有的代码在任何地方都不可用。我能够对大多数表使用MySQL内存引擎(对于某些表,如BLOB列,这是不可能的)
如果是真实的数据库,如何在每次测试运行之前从数据库中的dbData.xml恢复所有数据?
我编写了一个脚本,从远程测试服务器调用模式及其所有表的mysqldump,将它们插入本地服务器,并将所有可能的表引擎转换为内存。这确实需要时间,但由于模式在测试之间不会改变,因此它只能在最顶层的测试套件中运行一次,或者根据开发人员在本地系统上的需要单独运行一次
数据集在每个测试开始时加载,由于表已经存在并且在内存中,所以测试之间的插入和截断速度很快
我应该在哪里调用getConnection()和getDataSet()?
我们已经有了一个扩展TestCase的helper类,所以我不能使用PHPUnit\u Extensions\u Database\u TestCase。我将设置函数添加到该helper类中,从未调用或必须实现getDataSet()。我确实使用了getConnection()从assert函数中修改的数据创建了数据集
/**
* @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文档的一些资源书签有点不足:
我知道,我没有发布整个文件(我还编辑了列数…),你的答案是对的。这就像我写的第一个版本的测试。但是现在我真的需要测试这个查询。问题不在于测试结果,而在于找到一种方便的方法来提供可供实际查询执行使用的测试数据,并替换默认的PDO实例。我将编辑我的问题以反映。。。谢谢你的输入!
/**
* @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));
}