Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to functional-test a console's command input validator

I want to functional-test a Symfony's command I'm creating. I'm taking advantage of the Question helper class, by associating a personal validator:

    $helper = $this->getHelper('question');
    $question = new Question('Enter a valid IP: ');
    $question->setValidator($domainValidator);
    $question->setMaxAttempts(2);

the tests I'm performing are functionals, so in order to mock the interaction I added something like the following to my PHPUnit's test class. Here's an excerpt:

public function testBadIpRaisesError()
{
            $question = $this->createMock('Symfony\Component\Console\Helper\QuestionHelper');
            $question
                ->method('ask')
                ->will($this->onConsecutiveCalls(
                    '<IP>',
                    true
                ));
    ...
}

protected function createMock($originalClassName)
{
    return $this->getMockBuilder($originalClassName)
                ->disableOriginalConstructor()
                ->disableOriginalClone()
                ->disableArgumentCloning()
                ->disallowMockingUnknownTypes()
                ->getMock();
}

of course this mock is more than ok when I'm testing something that goes beyond the Question helper, but in this case what I'd like to do is testing the whole thing in order to make sure the validator is well written.

What's the best option in this case? Unit testing my validator is OK, but I would like to functional-testing it as a black box by the user point of view

like image 848
Bertuz Avatar asked Oct 14 '25 03:10

Bertuz


1 Answers

The Console component provides a CommandTester for precisely this use case: https://symfony.com/doc/current/console.html#testing-commands. You probably want to do something like this:

<?php

class ExampleCommandTest extends \PHPUnit\Framework\TestCase
{
    public function testBadIpRaisesError()
    {
        // For a command 'bin/console example'.
        $commandName = 'example';

        // Set up your Application with your command.
        $application = new \Symfony\Component\Console\Application();
        // Here's where you would inject any mocked dependencies as needed.
        $createdCommand = new WhateverCommand();
        $application->add($createdCommand);
        $foundCommand = $application->find($commandName);

        // Create a CommandTester with your Command class processed by your Application.
        $tester = new \Symfony\Component\Console\Tester\CommandTester($foundCommand);

        // Respond "y" to the first prompt (question) when the command is invoked.
        $tester->setInputs(['y']);

        // Execute the command. This example would be the equivalent of
        // 'bin/console example 127.0.0.1 --ipv6=true'
        $tester->execute([
            'command' => $commandName,
            // Arguments as needed.
            'ip-address' => '127.0.0.1',
            // Options as needed.
            '--ipv6' => true,
        ]);
        
        self::assert('Example output', $tester->getDisplay());
        self::assert(0, $tester->getStatusCode());
    }
}

You can see some more sophisticated working examples in a project I'm working on: https://github.com/php-tuf/composer-stager/blob/v0.1.0/tests/Unit/Console/Command/StageCommandTest.php

like image 86
TravisCarden Avatar answered Oct 17 '25 12:10

TravisCarden



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!