【发布时间】:2020-11-21 04:05:46
【问题描述】:
我正在使用 SQLite 连接和原则迁移来使用 PHPUnit 进行功能测试。
我正在使用setUp 方法从头开始迁移数据库:
public function setUp()
{
parent::setUp();
@unlink(__DIR__ . '/../../../../../../../var/sqlite.db');
exec('./vendor/bin/doctrine-migrations migrations:migrate --db-configuration=migrations-db-test.php --configuration=migrations_test.yml --no-interaction');
}
然后我可以从数据库中写入/读取。例如:
public function test_add_event_should_add_event()
{
$service = $this->getAdEventComparativesUpdateService();
$request = AdEventComparativesUpdateServiceRequest::make(self::AD_ID, self::USER_IP);
$response = $service->execute($request);
$this->assertEquals(1, $response->getTotal());
}
它有效。即使我使用相同的参数调用两次服务,它也确实有效。在这种情况下,它只需要写第一次:
public function test_add_two_same_events_should_add_one_event()
{
$service = $this->getAdEventComparativesUpdateService();
$request = AdEventComparativesUpdateServiceRequest::make(self::AD_ID, self::USER_IP);
// Call twice
$service->execute($request);
$response = $service->execute($request);
$this->assertEquals(1, $response->getTotal());
}
当我必须测试两个必须同时编写的调用时,问题就来了:
public function test_add_two_different_events_should_add_two_events()
{
$service = $this->getAdEventComparativesUpdateService();
$request = AdEventComparativesUpdateServiceRequest::make(self::AD_ID, self::USER_IP);
$response = $service->execute($request);
$service = $this->getAdEventComparativesUpdateService();
$request = AdEventComparativesUpdateServiceRequest::make(self::AD_ID, self::OTHER_USER_IP);
$response = $service->execute($request); // **** It fails here
$this->assertEquals(2, $response->getTotal());
}
错误来了:
- XXX::test_add_two_different_events_should_add_two_event Doctrine\DBAL\Exception\ReadOnlyException: 使用参数 [xxx, "xxx", "xxx", 执行 'INSERT INTO xxx (xxx, xxx, xxx, xxx) VALUES (?, ?, ?, ?)' 时发生异常, “xxx”]:
SQLSTATE[HY000]:一般错误:8 次尝试写入只读数据库
xxx/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php:78 xxx/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:128 xxx/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php:178 xxx/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:281 xxx/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:1014 xxx/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:378 xxx/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:356 xxx/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:235 xxx/DoctrineSession.php:32 xxx/TransactionalApplicationService.php:39 xxx/xxx/test.php:100
我尝试在调用之间更改数据库文件权限,但没有任何变化:
public function test_add_two_different_events_should_add_two_event()
{
$service = $this->getAdEventComparativesUpdateService();
$request = AdEventComparativesUpdateServiceRequest::make(self::AD_ID, self::USER_IP);
$response = $service->execute($request);
chmod(__DIR__ . '/../../../../../../../var', 0777);
chmod(__DIR__ . '/../../../../../../../var/sqlite.db', 0777);
chown(__DIR__ . '/../../../../../../../var', 'www-data');
chgrp(__DIR__ . '/../../../../../../../var', 'www-data');
chown(__DIR__ . '/../../../../../../../var/sqlite.db', 'www-data');
chgrp(__DIR__ . '/../../../../../../../var/sqlite.db', 'www-data');
//die;
// Here I checked the /var sqlite.db permissions. They are 0777
$service = $this->getAdEventComparativesUpdateService();
$request = AdEventComparativesUpdateServiceRequest::make(self::AD_ID, self::OTHER_USER_IP);
$response = $service->execute($request);
$this->assertEquals(2, $response->getTotal());
}
知道错误可能来自哪里吗?在这种情况下,每个服务调用都会调用persist + flush。
【问题讨论】:
-
@d3javu999 这就是我所做的
-
这是在黑暗中刺伤,因为我不知道教义...我可以设想“真正的”错误可能不是数据库是只读的,但它以某种方式被锁定。 也许(而且我处于危险之中)事情是异步发生的,
getTotal()调用会同步事情吗?如果是这样(大“如果”),则可能是两个更新都试图同时运行。如果您在第一个execute()之后添加$this->assertEquals(1, $response->getTotal());有什么变化吗? -
@Manolo 如果开启extended result codes,原始的sqlite状态码可以比'readonly'更具体。
-
@JánosRoden 我试过
$this->setAttribute(PDO::SQLITE_ATTR_EXTENDED_RESULT_CODES, true);但我得到这个错误:致命错误:未定义的类常量'SQLITE_ATTR_EXTENDED_RESULT_CODES'
标签: php sqlite doctrine phpunit doctrine-migrations