php - Why does Symfony DI container multiplies instances of a service when API tests are run?
问题描述
I have a service that should have only one instance and I was sure that DI container takes care about it. And when I send a request by Postman everything works properly, container returns always the very same instance. I have even added an additional field with a random number generated during object creation for debugging.
class ReadModel
{
private ?Database $database;
// Temporary field for debugging purpose
private int $tmp;
public function __construct()
{
$this->database = null;
$this->tmp = rand(1, 1000);
}
public function setDatabase(Database $database): void
{
$this->database = $database;
dump($this->tmp); // returns e.g. 836 when codeception test is run
}
public function getCollection(string $collectionName): Collection
{
dump($this->tmp); // returns e.g. 390 when codeception test is run
return $this->database->selectCollection($collectionName);
}
}
When a request is sent by Postman (dev environment) both numbers returned by dump()
function are equal (the same instance is injected to other services that uses it). But when I run a Codeception test, this service behaves differently. When I call setDatabase()
method of ReadModel
in one service and getCollection
methond in another one, I receive two different values of $tmp
field. That means that two different instances of ReadModel
service have been injected to my services. How is it possible and what can I do to have the same behavior in both environments (dev and test)?
ReadModel
service is autowired so I don't paste services.yaml
content.
My stack: Symfony 5.1, Codeception 4.1
PS. By Codeception tests I mean end2end API tests like this one, not unit tests:
<?php
use Codeception\Util\HttpCode;
class CreateProductCest
{
public function _before(ApiTester $I)
{
// Authentication stuff...
}
public function shouldCreateProductWithNoException(ApiTester $I)
{
$data = [
'name' => 'test123',
];
$I->sendPost('/product/create', $data);
$I->seeResponseIsJson();
$I->seeResponseCodeIs(HttpCode::OK);
$I->seeResponseContainsJson([]);
}
}
Examples of method calls of ReadModel
object. Most of the code is cut off, I leaved only relevant parts of code.
class JwtDecodedListener
{
private ReadModel $readModel;
public function __construct(
ReadModel $readModel
) {
$this->readModel = $readModel;
}
public function onJWTDecoded(JWTDecodedEvent $event)
{
// some code
$client = new Client("mongodb://{$mongoDbUser}:{$mongoDbPass}@{$this->mongoHost}/{$mongoDb}");
$this->readModel->setDatabase($client->selectDatabase($mongoDbUser));
}
}
class ProductProjection
{
private ReadModel $readModel;
public function __construct(
ReadModel $readModel
) {
$this->readModel = $readModel;
}
public function whenProductWasCreated(Product $product): void
{
// $collectionName is from a factory
$collection = $this->readModel->getCollection($collectionName);
}
}
Edit: As suggested in the comments I added dump()
call in the constructor of ReadModel
class and my conclusion is the same. Post request executed from postman - one constructor cal. The same request executed by Codeception - 2 constructor calls. Still have no idea what's the reason.
解决方案
推荐阅读
- applescript - 如何从我的调用者脚本访问外部 AppleScript 库
- https - 必发 Tcl 登录脚本
- smartsheet-api - Smart Sheet API 2.0 - 访问用户/我时出现错误代码 1004
- sql - SQL Snowflake - 在一张表中比较 2 个日期
- arrays - 在按钮上颤动显示firestore数据数组
- reactjs - 如何等待redux调度调用的完成
- mysql - 在我的数据库中插入双精度似乎忽略了 (M,D) 浮点语法
- python - Python:ThreadPoolExecutor 输出问题
- mule4 - 调用soapkit流时MUnit 2测试中的Mule 4出错,说流不存在,即使它存在
- php - 试图获取非对象的属性