这是我的测试没有按预期工作。我的测试类扩展了 PHPUnit_Extensions_Database_TestCase ,在每次测试运行之前,所有表都被截断并填充下面显示的数据集。
class NumberMapperTest extends PHPUnit_Extensions_Database_TestCase {
private $dsn = 'mysql:host=...;dbname=test;port=3306;charset=utf8';
private $conn = null;
private $numberMapper;
protected function getConnection() {
if ($this->conn === null) {
$pdo = new PDO($this->dsn, '...', '...');
$this->conn = $this->createDefaultDBConnection($pdo, 'test');
}
return $this->conn;
}
public function getDataSet() {
$compositeDs = new PHPUnit_Extensions_Database_DataSet_CompositeDataSet(array());
$ds = $this->createMySQLXMLDataSet('fixtures/number.xml');
$compositeDs->addDataSet($ds);
return $compositeDs;
}
public function setUp() {
$conn = $this->getConnection();
$pdo = $conn->getConnection();
$pdo->exec('SET foreign_key_checks = 0');
parent::setUp();
$pdo->exec('SET foreign_key_checks = 1');
$databaseAdapter = new DatabaseAdapter($pdo);
$this->numberMapper = new NumberMapper($databaseAdapter);
}
public function tearDown() {
$conn = $this->getConnection();
$pdo = $conn->getConnection();
$pdo->exec('SET foreign_key_checks = 0');
parent::tearDown();
$pdo->exec('SET foreign_key_checks = 1');
}
protected function getTearDownOperation() {
return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
/**
* @test
* @covers Classes\Mapper\NumberMapper::findByUid
*/
public function findByUidReturnsExpectedNumber() {
$expectedNumber = new Number(1, 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
$this->assertEquals($expectedNumber, $this->numberMapper->findByUid('AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA'));
}
}
测试引发以下异常:
InvalidArgumentException: The number ['1'] is invalid.
正如你在''(引号)上看到的那样,数字是以字符串而不是数字的形式返回的,我不知道为什么。因为它存储为测试数据库中的数字。我可以确认,在测试运行后没有截断表,并使用一个小脚本连接到我的测试数据库并运行它。一切都按预期工作 - 创建一个Number对象。
<?php
...
$adapter = new DatabaseAdapter($pdo);
$numberMapper = new NumberMapper($adapter);
var_dump($numberMapper->findByUid('AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA'));
所以我的代码似乎工作正常,但我的测试失败(抛出异常)。我发现无法为我的测试数据集中的列指定数据类型。也许存在问题,因为看起来所有值都被视为字符串。但正如所说的那样,数字作为数字正确存储到数据库中。有人可以解释这种行为的原因是什么,因为我很无能。
我的测试数据库有一个带有以下模式的数字表:
CREATE TABLE `number` (
`uid` CHAR(36) NOT NULL DEFAULT '',
`number` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`uid`),
UNIQUE INDEX `number` (`number`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
要使用PHPUnit测试我的NumberMapper,我使用了以下数据集[fixtures / number.xml]:
<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="test">
<table_data name="number">
<row>
<field name="uid">AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA</field>
<field name="number">1</field>
</row>
</table_data>
</database>
</mysqldump>
我要测试的NumberMapper:
class NumberMapper {
private $adapter;
public function __construct($adapter) {
$this->adapter = $adapter;
}
public function findByUid($uid) {
$this->adapter
->select(array('uid', 'number'))
->from('number')
->where('uid = :uid')
->bindParameters(array(':uid' => $uid));
return $this->createEntity($this->adapter->fetch());
}
public function createEntity(array $data) {
if (isset($data['number'])) {
$uid = isset($data['uid']) ? $data['uid'] : $this->generateUid();
return new Number($data['number'], $uid);
} else {
return new NullNumber();
}
}
}
我的号码域模型如下所示:
class Number {
/**
* @var string
*/
private $uid;
/**
* @var int
*/
private $number;
public function __construct($number, $uid) {
$this->setUid($uid);
$this->setNumber($number);
}
public function setUid($uid) {
if (!is_string($uid) || strlen($uid) !== 36) {
throw new InvalidArgumentException('The uid [' . var_export($uid, TRUE) . '] is invalid.');
}
$this->uid = $uid;
}
public function setNumber($number) {
if (is_numeric($number) && !is_string($number) && 0 <= $number && $number <= 4294967295 === FALSE) {
throw new InvalidArgumentException('The number [' . var_export($number, TRUE) . '] is invalid.');
}
$this->number = $number;
}
}
答案 0 :(得分:0)
我找到了解决问题的方法,所以我仍然不知道为什么我必须这样做。我注意到我的小脚本和测试代码确实存在差异。在我的脚本中,我有一些PDO属性集,我在测试中也设置了这些属性集。 PDO :: ATTR_EMULATE_PREPARES 属性是重要的属性。一旦我在测试中将其设置为false,一切都按预期工作。我现在也在我的测试中设置 ATTR_ERRMODE ,以便我的getConnection方法现在看起来像这样:
protected function getConnection() {
if ($this->conn === null) {
$pdo = new PDO($this->dsn, '...', '...');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->conn = $this->createDefaultDBConnection($pdo, 'test');
}
return $this->conn;
}