Skip to content

Commit db16346

Browse files
dunglasweaverryan
authored andcommitted
Add a new make:test command
1 parent bc7ccf1 commit db16346

19 files changed

+421
-12
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1+
1.29
2+
====
3+
4+
* [make:test] Added the maker
5+
* [make:unit-test] Deprecated the maker
6+
* [make:functional-test] Deprecated the maker
7+
18
1.27
9+
====
210

311
* [make:registration-form] Added a new question to generate code that will allow
412
users to click on the "verify email" link in their email without needing to be

src/DependencyInjection/CompilerPass/MakeCommandRegistrationPass.php

+13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public function process(ContainerBuilder $container)
2929
{
3030
foreach ($container->findTaggedServiceIds(self::MAKER_TAG) as $id => $tags) {
3131
$def = $container->getDefinition($id);
32+
if ($def->isDeprecated()) {
33+
continue;
34+
}
35+
3236
$class = $container->getParameterBag()->resolveValue($def->getClass());
3337
if (!is_subclass_of($class, MakerInterface::class)) {
3438
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, MakerInterface::class));
@@ -50,6 +54,15 @@ public function process(ContainerBuilder $container)
5054

5155
$commandDefinition->addTag('console.command', $tagAttributes);
5256

57+
/*
58+
* @deprecated remove this block when removing make:unit-test and make:functional-test
59+
*/
60+
if (method_exists($class, 'getCommandAliases')) {
61+
foreach ($class::getCommandAliases() as $alias) {
62+
$commandDefinition->addTag('console.command', ['command' => $alias, 'description' => 'Deprecated alias of "make:test"']);
63+
}
64+
}
65+
5366
$container->setDefinition(sprintf('maker.auto_command.%s', Str::asTwigVariable($class::getCommandName())), $commandDefinition);
5467
}
5568
}

src/DependencyInjection/MakerExtension.php

+17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Bundle\MakerBundle\MakerInterface;
1616
use Symfony\Component\Config\FileLocator;
1717
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
use Symfony\Component\DependencyInjection\Definition;
1819
use Symfony\Component\DependencyInjection\Loader;
1920
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
2021

@@ -25,6 +26,11 @@
2526
*/
2627
class MakerExtension extends Extension
2728
{
29+
/**
30+
* @deprecated remove this block when removing make:unit-test and make:functional-test
31+
*/
32+
private const TEST_MAKER_DEPRECATION_MESSAGE = 'The "%service_id%" service is deprecated, use "maker.maker.make_test" instead.';
33+
2834
/**
2935
* {@inheritdoc}
3036
*/
@@ -34,6 +40,17 @@ public function load(array $configs, ContainerBuilder $container)
3440
$loader->load('services.xml');
3541
$loader->load('makers.xml');
3642

43+
/**
44+
* @deprecated remove this block when removing make:unit-test and make:functional-test
45+
*/
46+
$deprecParams = method_exists(Definition::class, 'getDeprecation') ? ['symfony/maker-bundle', '1.29', self::TEST_MAKER_DEPRECATION_MESSAGE] : [true, self::TEST_MAKER_DEPRECATION_MESSAGE];
47+
$container
48+
->getDefinition('maker.maker.make_unit_test')
49+
->setDeprecated(...$deprecParams);
50+
$container
51+
->getDefinition('maker.maker.make_functional_test')
52+
->setDeprecated(...$deprecParams);
53+
3754
$configuration = $this->getConfiguration($configs, $container);
3855
$config = $this->processConfiguration($configuration, $configs);
3956

src/Maker/MakeFunctionalTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
use Symfony\Component\CssSelector\CssSelectorConverter;
2424
use Symfony\Component\Panther\PantherTestCaseTrait;
2525

26+
trigger_deprecation('symfony/maker-bundle', '1.29', 'The "%s" class is deprecated, use "%s" instead.', MakeFunctionalTest::class, MakeTest::class);
27+
2628
/**
29+
* @deprecated since MakerBundle 1.29, use Symfony\Bundle\MakerBundle\Maker\MakeTest instead.
30+
*
2731
* @author Javier Eguiluz <[email protected]>
2832
* @author Ryan Weaver <[email protected]>
2933
*/

src/Maker/MakeTest.php

+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony MakerBundle package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\MakerBundle\Maker;
13+
14+
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
15+
use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait;
16+
use Symfony\Bundle\MakerBundle\ConsoleStyle;
17+
use Symfony\Bundle\MakerBundle\DependencyBuilder;
18+
use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
19+
use Symfony\Bundle\MakerBundle\Generator;
20+
use Symfony\Bundle\MakerBundle\InputAwareMakerInterface;
21+
use Symfony\Bundle\MakerBundle\InputConfiguration;
22+
use Symfony\Component\BrowserKit\History;
23+
use Symfony\Component\Console\Command\Command;
24+
use Symfony\Component\Console\Input\InputArgument;
25+
use Symfony\Component\Console\Input\InputInterface;
26+
use Symfony\Component\CssSelector\CssSelectorConverter;
27+
use Symfony\Component\Panther\PantherTestCaseTrait;
28+
29+
/**
30+
* @author Kévin Dunglas <[email protected]>
31+
* @author Javier Eguiluz <[email protected]>
32+
* @author Ryan Weaver <[email protected]>
33+
*/
34+
final class MakeTest extends AbstractMaker implements InputAwareMakerInterface
35+
{
36+
private const DESCRIPTIONS = [
37+
'TestCase' => 'basic PHPUnit tests',
38+
'KernelTestCase' => 'basic tests that have access to Symfony services',
39+
'WebTestCase' => 'to run browser-like scenarios, but that don\'t execute JavaScript code',
40+
'ApiTestCase' => 'to run API-oriented scenarios',
41+
'PantherTestCase' => 'to run e2e scenarios, using a real-browser or HTTP client and a real web server',
42+
];
43+
private const DOCS = [
44+
'TestCase' => 'https://symfony.com/doc/current/testing.html#unit-tests',
45+
'KernelTestCase' => 'https://symfony.com/doc/current/testing/database.html#functional-testing-of-a-doctrine-repository',
46+
'WebTestCase' => 'https://symfony.com/doc/current/testing.html#functional-tests',
47+
'ApiTestCase' => 'https://api-platform.com/docs/distribution/testing/',
48+
'PantherTestCase' => 'https://github.com/symfony/panther#testing-usage',
49+
];
50+
51+
public static function getCommandName(): string
52+
{
53+
return 'make:test';
54+
}
55+
56+
/**
57+
* @deprecated remove this method when removing make:unit-test and make:functional-test
58+
*/
59+
public static function getCommandAliases(): iterable
60+
{
61+
yield 'make:unit-test';
62+
yield 'make:functional-test';
63+
}
64+
65+
public static function getCommandDescription(): string
66+
{
67+
return 'Creates a new test class';
68+
}
69+
70+
public function configureCommand(Command $command, InputConfiguration $inputConf)
71+
{
72+
$typesDesc = [];
73+
$typesHelp = [];
74+
foreach (self::DESCRIPTIONS as $type => $desc) {
75+
$typesDesc[] = sprintf('<fg=yellow>%s</> (%s)', $type, $desc);
76+
$typesHelp[] = sprintf('* <info>%s</info>: %s', $type, $desc);
77+
}
78+
79+
$command
80+
->addArgument('name', InputArgument::OPTIONAL, 'The name of the test class (e.g. <fg=yellow>BlogPostTest</>)')
81+
->addArgument('type', InputArgument::OPTIONAL, 'The type of test: '.implode(', ', $typesDesc))
82+
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeTest.txt').implode("\n", $typesHelp));
83+
84+
$inputConf->setArgumentAsNonInteractive('type');
85+
}
86+
87+
public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
88+
{
89+
/* @deprecated remove the following block when removing make:unit-test and make:functional-test */
90+
$currentCommand = $input->getFirstArgument();
91+
switch ($currentCommand) {
92+
case 'make:unit-test':
93+
$input->setArgument('type', 'TestCase');
94+
$io->caution('The "make:unit-test" command is deprecated, use "make:test" instead.');
95+
96+
return;
97+
98+
case 'make:functional-test':
99+
$input->setArgument('type', trait_exists(PantherTestCaseTrait::class) ? 'WebTestCase' : 'PantherTestCase');
100+
$io->caution('The "make:functional-test" command is deprecated, use "make:test" instead.');
101+
102+
return;
103+
}
104+
105+
if (null !== $type = $input->getArgument('type')) {
106+
if (!isset(self::DESCRIPTIONS[$type])) {
107+
throw new RuntimeCommandException(sprintf('The test type must be one of "%s", "%s" given.', implode('", "', array_keys(self::DESCRIPTIONS)), $type));
108+
}
109+
110+
return;
111+
}
112+
113+
$input->setArgument(
114+
'type',
115+
$io->choice('Which test type would you like?', self::DESCRIPTIONS)
116+
);
117+
}
118+
119+
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
120+
{
121+
$testClassNameDetails = $generator->createClassNameDetails(
122+
$input->getArgument('name'),
123+
'Tests\\',
124+
'Test'
125+
);
126+
127+
$type = $input->getArgument('type');
128+
129+
$generator->generateClass(
130+
$testClassNameDetails->getFullName(),
131+
"test/$type.tpl.php",
132+
['web_assertions_are_available' => trait_exists(WebTestAssertionsTrait::class)]
133+
);
134+
135+
$generator->writeChanges();
136+
137+
$this->writeSuccessMessage($io);
138+
139+
$io->text([
140+
'Next: Open your new test class and start customizing it.',
141+
sprintf('Find the documentation at <fg=yellow>%s</>', self::DOCS[$type]),
142+
]);
143+
}
144+
145+
public function configureDependencies(DependencyBuilder $dependencies, InputInterface $input = null): void
146+
{
147+
if (null === $input) {
148+
return;
149+
}
150+
151+
switch ($input->getArgument('type')) {
152+
case 'WebTestCase':
153+
$dependencies->addClassDependency(
154+
History::class,
155+
'browser-kit',
156+
true,
157+
true
158+
);
159+
$dependencies->addClassDependency(
160+
CssSelectorConverter::class,
161+
'css-selector',
162+
true,
163+
true
164+
);
165+
166+
return;
167+
168+
case 'ApiTestCase':
169+
$dependencies->addClassDependency(
170+
ApiTestCase::class,
171+
'api',
172+
true,
173+
false
174+
);
175+
176+
return;
177+
178+
case 'PantherTestCase':
179+
$dependencies->addClassDependency(
180+
PantherTestCaseTrait::class,
181+
'panther',
182+
true,
183+
true
184+
);
185+
186+
return;
187+
}
188+
}
189+
}

src/Maker/MakeUnitTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
use Symfony\Component\Console\Input\InputArgument;
2020
use Symfony\Component\Console\Input\InputInterface;
2121

22+
trigger_deprecation('symfony/maker-bundle', '1.29', 'The "%s" class is deprecated, use "%s" instead.', MakeUnitTest::class, MakeTest::class);
23+
2224
/**
25+
* @deprecated since MakerBundle 1.29, use Symfony\Bundle\MakerBundle\Maker\MakeTest instead.
26+
*
2327
* @author Javier Eguiluz <[email protected]>
2428
* @author Ryan Weaver <[email protected]>
2529
*/

src/Resources/config/makers.xml

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@
9999
<tag name="maker.command" />
100100
</service>
101101

102+
<service id="maker.maker.make_test" class="Symfony\Bundle\MakerBundle\Maker\MakeTest">
103+
<tag name="maker.command" />
104+
</service>
105+
102106
<service id="maker.maker.make_unit_test" class="Symfony\Bundle\MakerBundle\Maker\MakeUnitTest">
103107
<tag name="maker.command" />
104108
</service>

src/Resources/help/MakeTest.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
The <info>%command.name%</info> command generates a new test class.
2+
3+
<info>php %command.full_name% BlogPostTest TestCase</info>
4+
5+
If the first argument is missing, the command will ask for the class name interactively.
6+
7+
If the second argument is missing, the command will ask for the test type interactively.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?= "<?php\n" ?>
2+
3+
namespace <?= $namespace; ?>;
4+
5+
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
6+
7+
class <?= $class_name ?> extends ApiTestCase
8+
{
9+
public function testSomething(): void
10+
{
11+
$response = static::createClient()->request('GET', '/');
12+
13+
$this->assertResponseIsSuccessful();
14+
$this->assertJsonContains(['@id' => '/']);
15+
}
16+
}

src/Resources/skeleton/test/Functional.tpl.php

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<?php /* @deprecated remove this method when removing make:unit-test and make:functional-test */ ?>
12
<?= "<?php\n" ?>
23

34
namespace <?= $namespace; ?>;
@@ -10,16 +11,24 @@
1011

1112
class <?= $class_name ?> extends <?= $panther_is_available ? 'PantherTestCase' : 'WebTestCase' ?><?= "\n" ?>
1213
{
13-
public function testSomething()
14+
public function testSomething(): void
1415
{
16+
<?php if ($panther_is_available): ?>
17+
$client = static::createPantherClient();
18+
<?php else: ?>
1519
$client = static::createClient();
20+
<?php endif ?>
1621
$crawler = $client->request('GET', '/');
1722

1823
<?php if ($web_assertions_are_available): ?>
24+
<?php if (!$panther_is_available): ?>
1925
$this->assertResponseIsSuccessful();
26+
<?php endif ?>
2027
$this->assertSelectorTextContains('h1', 'Hello World');
2128
<?php else: ?>
29+
<?php if (!$panther_is_available): ?>
2230
$this->assertSame(200, $client->getResponse()->getStatusCode());
31+
<?php endif ?>
2332
$this->assertStringContainsString('Hello World', $crawler->filter('h1')->text());
2433
<?php endif ?>
2534
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?= "<?php\n" ?>
2+
3+
namespace <?= $namespace; ?>;
4+
5+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
6+
7+
class <?= $class_name ?> extends KernelTestCase
8+
{
9+
public function testSomething(): void
10+
{
11+
$kernel = self::bootKernel();
12+
13+
$this->assertSame('test', $kernel->getEnvironment());
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?= "<?php\n" ?>
2+
3+
namespace <?= $namespace; ?>;
4+
5+
use Symfony\Component\Panther\PantherTestCase;
6+
7+
class <?= $class_name ?> extends PantherTestCase
8+
{
9+
public function testSomething(): void
10+
{
11+
$client = static::createPantherClient();
12+
$crawler = $client->request('GET', '/');
13+
14+
<?php if ($web_assertions_are_available): ?>
15+
$this->assertSelectorTextContains('h1', 'Hello World');
16+
<?php else: ?>
17+
$this->assertStringContainsString('Hello World', $crawler->filter('h1')->text());
18+
<?php endif ?>
19+
}
20+
}

0 commit comments

Comments
 (0)