如何在测试控制台命令时模拟某些服务。我有一些控制台命令,在这个命令中我得到一些服务,我想要模拟这个服务
控制台命令
const APP_SATISFACTION_REPORT = 'app:satisfactionrepor';
protected function configure()
{
$this
->setName(self::APP_SATISFACTION_REPORT)
->setDescription('Send Satisfaction Report');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$container = $this->getContainer();
$serviceCompanyRepo = $container->get('app.repository.orm.service_company_repository');
$satisfactionReport = $container->get('app.services.satisfaction_report');
/** @var ServiceCompany $serviceCompany */
foreach ($serviceCompanyRepo->findAll() as $serviceCompany) {
try {
$satisfactionReport->sendReport($serviceCompany);
} catch (\Exception $e) {
$io->warning(sprintf(
'Failed to send satisfaction report for service company with ID %s',
$serviceCompany->getId()
));
}
}
}
和我的测试
/** @var Console\Application $application */
protected $application;
protected $container;
/** @var BufferedOutput $output */
protected $output;
/**
* @var ServiceCompanyRepository
*/
private $serviceCompanyRepository;
准备控制台命令
public function setUp()
{
parent::setUp();
$entityManager = $this->getEntityManager();
$this->serviceCompanyRepository = $entityManager->getRepository(ServiceCompany::class);
static::bootKernel();
$this->container = static::$kernel->getContainer();
$this->application = new Console\Application(static::$kernel);
$this->application->setAutoExit(false);
$master = new SatisfactionReportCommand();
$this->application->add($master);
}
public function setUpMaster() {
$this->output = new BufferedOutput();
$this->application->run(new ArgvInput([
'./bin/console',
SatisfactionReportCommand::APP_SATISFACTION_REPORT,
]), $this->output);
}
public function testGetMasterOutput()
{
$this->loadFixture(ServiceCompany::class);
/** @var ServiceCompany[] $serviceCompanies */
$serviceCompanies = $this->serviceCompanyRepository->findAll();
$this->assertCount(2, $serviceCompanies);
$client = self::createClient();
模拟服务app.services.satisfaction_report
$service = $this->getMockService($serviceCompanies);
并将其设置在容器中
$client->getContainer()->set('app.services.satisfaction_report', $service);
$this->setUpMaster();
$output = $this->output->fetch();
}
protected function getMockService($serviceCompanies)
{
$service = $this->getMockBuilder(SatisfactionReport::class)
->setMethods(['sendReport'])
->disableOriginalConstructor()
->getMock();
$service
->expects($this->exactly(2))
->method('sendReport')
->withConsecutive(
[$serviceCompanies[0]],
[$serviceCompanies[1]]
);
return $service;
}
如何模仿app.services.satisfaction_report
?设置在容器app.services.satisfaction_report
中没有帮助我
答案 0 :(得分:1)
我有同样的问题,但我解决了。
我有基类:
class TestCase extends WebTestCase
{
/** @var Application */
private $application;
private $mailServiceMock;
protected function setMailService(MailService $mailServiceMock): void
{
$this->mailServiceMock = $mailServiceMock;
}
protected function getApplication(): Application
{
static::bootKernel();
static::$kernel->getContainer()->get('test.client');
$this->setMocks();
$this->application = new Application(static::$kernel);
$this->application->setCatchExceptions(false);
$this->application->setAutoExit(false);
return $this->application;
}
protected function execute(string $action, array $arguments = [], array $inputs = []): CommandTester
{
$tester = (new CommandTester($this->getApplication()->find($action)))->setInputs($inputs);
$tester->execute($arguments);
return $tester;
}
private function setMocks(): void
{
if ($this->mailServiceMock) {
static::$kernel->getContainer()->set('mail', $this->mailServiceMock);
}
}
}
测试课
class SendEmailCommandTest extends TestCase
{
public function testExecuteSendingError(): void
{
$mailServiceMock = $this->getMockBuilder(MailService::class)->disableOriginalConstructor()
->setMethods(['sendEmail'])->getMock();
$mailServiceMock->method('sendEmail')->willThrowException(new \Exception());
$this->setMailService($mailServiceMock);
$tester = $this->execute(SendEmailCommand::COMMAND_NAME, self::NORMAL_PAYLOAD);
$this->assertEquals(SendEmailCommand::STATUS_CODE_EMAIL_SENDING_ERROR, $tester->getStatusCode());
}
}
正如您所见,我在启动内核后立即设置了mail
服务。
在这里,您可以看到我的services.yaml
:
services:
mail.command.send.email:
autowire: true
class: App\Command\SendEmailCommand
arguments: ["@logger", "@mail"]
tags:
- {name: console.command, command: "mail:send.email"}
答案 1 :(得分:0)
如果您将命令创建为service,框架会自动将服务(自动装配或使用显式参数列表)注入构造函数(提示:在命令中,调用{{1}然后,测试可以创建与参数typehint(或接口)匹配的任何模拟或其他替换服务。
答案 2 :(得分:0)
这是我的示例类:
class MainCommandTest extends IntegrationTestCase
{
/**
* @var MainCommand
*/
protected $subject;
/**
* @var Application
*/
protected $application;
/**
* sets test subject
*
* @return void
*/
public function setUp()
{
parent::setUp();
static::bootKernel();
$readStreams = new ReadStreams();
$udpStreamMock = $this->getMockBuilder(UdpStream::class)->disableOriginalConstructor()->setMethods(['readIncomingStreams'])->getMock();
$udpStreamMock->expects($this->once())->method('readIncomingStreams')->willReturn($readStreams);
static::$kernel->getContainer()->set(UdpStream::class, $udpStreamMock);
$application = new Application($this::$kernel);
$this->subject = $this->getService(MainCommand::class);
$application->add( $this->subject);
$this->application = $application;
}
/**
* Tests command in $subject command,
*
* @return void
*/
public function testCommand()
{
$command = $this->application->find( $this->subject->getName());
$commandTester = new CommandTester($command);
$commandTester->execute(
[
'command' => $this->subject->getName()
]
);
$this->stringContains($commandTester->getDisplay(true), 'finished');
$this->assertEquals($commandTester->getStatusCode(), 0);
}
}