I have problem with command test. I am trying to mock service inside command test, but there's problem that this mock isn't used in test.
Here are command code:
public function __construct(RpcClient $rpcClient, LoggerInterface $logger, EntityManagerInterface $entityManager)
{
$this->rpcClient = $rpcClient;
$this->logger = $logger;
$this->entityManager = $entityManager;
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$apiSecurityKey = $this->getContainer()->getParameter('api_security_key');
try {
$apiBoxesData = $this->rpcClient->callJsonRPCPostMethod("stations_info", ["apiSecurityKey" => $apiSecurityKey]);
.
.
.
And test:
//some of dependencies used
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
class SynchronizeBoxInfoCommandTest extends KernelTestCase
{
const SYNCHRONIZE_BOX_INFO_COMMAND_NAME = "app:synchronize-box-info";
public function setUp()
{
parent::setUp();
static::$kernel = static::createKernel();
static::$kernel->boot();
$application = new Application(static::$kernel);
$this->command = $application->find(self::SYNCHRONIZE_BOX_INFO_COMMAND_NAME);
$this->command->setApplication($application);
$this->commandTester = new CommandTester($this->command);
$this->entityManager = static::$kernel->getContainer()->get('doctrine.orm.entity_manager');
$logger = $this->createMock(LoggerInterface::class);
$this->rpcClientMock = $this->createMock(RpcClient::class);
$application->add(new SynchronizeBoxInfoCommand($this->rpcClientMock, $logger, $this->entityManager));
}
public function testFirstExecutionAllNewData()
{
$this->rpcClientMock->expects($this->once())
->method("callJsonRPCPostMethod")
->willReturn(["test"]);
$this->commandTester->execute([
'command' => $this->command,
]);
}
For this code, when I'm running test, command when command call method callJsonRPCPostMethod
it doesn't return mocked string "test" but it call real implementation of method, which makes call to api. I was searching whole internet and actually not find any of good answer that works for me.
I find out that adding command with mocked services to application at the end of setUp, after $this->command = $application->find(...)
ends up with using command before mocked services. So You should declare command with mocked services before You use find command that You want to test. This code below works for me now:
public function setUp()
{
$kernel = self::bootKernel();
$application = new Application($kernel);
$this->entityManager = static::$kernel->getContainer()->get('doctrine.orm.entity_manager');
$logger = $this->createMock(LoggerInterface::class);
$this->rpcClientMock = $this->createMock(RpcClient::class);
$application->add(new SynchronizeBoxInfoCommand($this->rpcClientMock, $logger, $this->entityManager));
$this->command = $application->find(self::SYNCHRONIZE_BOX_INFO_COMMAND_NAME);
$this->commandTester = new CommandTester($this->command);
}
It's hard to test such things in Symfony4. Try to do following:
1.Make service, which you want to mock, public
2.In test mock it:
$this->client = static::createClient();
static::$kernel->getContainer()->set($serviceId, $serviceMock);
$application = new Application(static::$kernel);
3.Use this $application
for command execution
$tester = (new CommandTester($application->find($commandName)))->setInputs($inputs);
$tester->execute($arguments);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With