Skip to content

Commit 767be43

Browse files
committed
feature #307 [make:crud][experimental] Add generated tests to make:crud (ckrack, jrushlow)
This PR was merged into the 1.0-dev branch. Discussion ---------- [make:crud][experimental] Add generated tests to make:crud Add tests for the controller methods. Add necessary dependencies. Closes #229 Edit by `@jrushlow`: - Feature is experimental - We generate a minimum WebTestCase for generated CRUD. - Generating tests is on an opt-in basis _if_ the user has `test-pack` already installed. Otherwise we're not advertising this feature yet. - Entity / Form Field guessing is not _fully_ implemented. "Setter" values other than `string` will not match the Entity's property types and must be manually changed. - Tests (other than `testIndex()`) are all generated with `markTestIncomplete()` - Better integration w/ Panther, Fixtures, Foundry, etc... to come in future PR's Commits ------- 3d9adfb check for WebTestCase 4cb0d14 fix method call 9b1990f warn user if testpack is not installed after we generate the test 6a1dfe9 type hints for php 7.4 < 88b5f41 conditionally use typed properties b87f148 cleanup 9592d08 lets not do this yet 036b9c5 handel entity manager && custom repo tests 3c5ac73 annotation / attribute tests a061aed refactor index test ac588d3 refactor test a2ded0a Crud: Add test for test-generation b9f2036 Crud: Isolate & improve generated tests 351dc63 Crud: Make tests optional & fix renamed browser-kit class b08b425 Tabs to Spaces 3033732 Fix indenting & TODO 523af32 Optimize generated test 67ff18e Pass only used variables to template a748362 Comment out to pass tests b6aab44 Add generated tests to make:crud
2 parents e2d6c94 + 3d9adfb commit 767be43

File tree

4 files changed

+352
-15
lines changed

4 files changed

+352
-15
lines changed

src/Maker/MakeCrud.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
1515
use Doctrine\Inflector\InflectorFactory;
1616
use Doctrine\ORM\EntityManagerInterface;
17+
use Doctrine\ORM\EntityRepository;
1718
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
1819
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
20+
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
21+
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
1922
use Symfony\Bundle\MakerBundle\ConsoleStyle;
2023
use Symfony\Bundle\MakerBundle\DependencyBuilder;
2124
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
@@ -46,6 +49,7 @@ final class MakeCrud extends AbstractMaker
4649
private $formTypeRenderer;
4750
private $inflector;
4851
private $controllerClassName;
52+
private $generateTests = false;
4953

5054
public function __construct(DoctrineHelper $doctrineHelper, FormTypeRenderer $formTypeRenderer)
5155
{
@@ -95,6 +99,8 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma
9599
sprintf('Choose a name for your controller class (e.g. <fg=yellow>%s</>)', $defaultControllerClass),
96100
$defaultControllerClass
97101
);
102+
103+
$this->generateTests = $io->confirm('Do you want to generate tests for the controller?. [Experimental]', false);
98104
}
99105

100106
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
@@ -232,6 +238,49 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
232238
);
233239
}
234240

241+
if ($this->generateTests) {
242+
$testClassDetails = $generator->createClassNameDetails(
243+
$entityClassDetails->getRelativeNameWithoutSuffix(),
244+
'Test\\Controller\\',
245+
'ControllerTest'
246+
);
247+
248+
$useStatements = new UseStatementGenerator([
249+
$entityClassDetails->getFullName(),
250+
WebTestCase::class,
251+
KernelBrowser::class,
252+
$repositoryClassName,
253+
]);
254+
255+
$usesEntityManager = EntityManagerInterface::class === $repositoryClassName;
256+
257+
if ($usesEntityManager) {
258+
$useStatements->addUseStatement(EntityRepository::class);
259+
}
260+
261+
$generator->generateFile(
262+
'tests/Controller/'.$testClassDetails->getShortName().'.php',
263+
$usesEntityManager ? 'crud/test/Test.EntityManager.tpl.php' : 'crud/test/Test.tpl.php',
264+
[
265+
'use_statements' => $useStatements,
266+
'entity_full_class_name' => $entityClassDetails->getFullName(),
267+
'entity_class_name' => $entityClassDetails->getShortName(),
268+
'entity_var_singular' => $entityVarSingular,
269+
'route_path' => Str::asRoutePath($controllerClassDetails->getRelativeNameWithoutSuffix()),
270+
'route_name' => $routeName,
271+
'class_name' => Str::getShortClassName($testClassDetails->getFullName()),
272+
'namespace' => Str::getNamespace($testClassDetails->getFullName()),
273+
'form_fields' => $entityDoctrineDetails->getFormFields(),
274+
'repository_class_name' => $usesEntityManager ? EntityManagerInterface::class : $repositoryVars['repository_class_name'],
275+
'form_field_prefix' => strtolower(Str::asSnakeCase($entityTwigVarSingular)),
276+
]
277+
);
278+
279+
if (!class_exists(WebTestCase::class)) {
280+
$io->caution('You\'ll need to install the `symfony/test-pack` to execute the tests for your new controller.');
281+
}
282+
}
283+
235284
$generator->writeChanges();
236285

237286
$this->writeSuccessMessage($io);
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?= "<?php\n" ?>
2+
<?php use Symfony\Bundle\MakerBundle\Str; ?>
3+
4+
namespace <?= $namespace ?>;
5+
6+
<?= $use_statements; ?>
7+
8+
class <?= $class_name ?> extends WebTestCase<?= "\n" ?>
9+
{
10+
<?= $use_typed_properties ? null : " /** @var KernelBrowser */\n" ?>
11+
private <?= $use_typed_properties ? 'KernelBrowser ' : null ?>$client;
12+
<?= $use_typed_properties ? null : " /** @var EntityManagerInterface */\n" ?>
13+
private <?= $use_typed_properties ? 'EntityManagerInterface ' : null ?>$manager;
14+
<?= $use_typed_properties ? null : " /** @var EntityRepository */\n" ?>
15+
private <?= $use_typed_properties ? 'EntityRepository ' : null ?>$repository;
16+
private <?= $use_typed_properties ? 'string ' : null ?>$path = '<?= $route_path; ?>/';
17+
18+
protected function setUp(): void
19+
{
20+
$this->client = static::createClient();
21+
$this->manager = (static::getContainer()->get('doctrine'))->getManager();
22+
$this->repository = $this->manager->getRepository(<?= $entity_class_name; ?>::class);
23+
24+
foreach ($this->repository->findAll() as $object) {
25+
$this->manager->remove($object);
26+
}
27+
28+
$this->manager->flush();
29+
}
30+
31+
public function testIndex(): void
32+
{
33+
$crawler = $this->client->request('GET', $this->path);
34+
35+
self::assertResponseStatusCodeSame(200);
36+
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?> index');
37+
38+
// Use the $crawler to perform additional assertions e.g.
39+
// self::assertSame('Some text on the page', $crawler->filter('.p')->first());
40+
}
41+
42+
public function testNew(): void
43+
{
44+
$this->markTestIncomplete();
45+
$this->client->request('GET', sprintf('%snew', $this->path));
46+
47+
self::assertResponseStatusCodeSame(200);
48+
49+
$this->client->submitForm('Save', [
50+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
51+
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Testing',
52+
<?php endforeach; ?>
53+
]);
54+
55+
self::assertResponseRedirects('/sweet/food/');
56+
57+
self::assertSame(1, $this->getRepository()->count([]));
58+
}
59+
60+
public function testShow(): void
61+
{
62+
$this->markTestIncomplete();
63+
$fixture = new <?= $entity_class_name; ?>();
64+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
65+
$fixture->set<?= ucfirst($form_field); ?>('My Title');
66+
<?php endforeach; ?>
67+
68+
$this->repository->add($fixture, true);
69+
70+
$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));
71+
72+
self::assertResponseStatusCodeSame(200);
73+
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?>');
74+
75+
// Use assertions to check that the properties are properly displayed.
76+
}
77+
78+
public function testEdit(): void
79+
{
80+
$this->markTestIncomplete();
81+
$fixture = new <?= $entity_class_name; ?>();
82+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
83+
$fixture->set<?= ucfirst($form_field); ?>('Value');
84+
<?php endforeach; ?>
85+
86+
$this->manager->persist($fixture);
87+
$this->manager->flush();
88+
89+
$this->client->request('GET', sprintf('%s%s/edit', $this->path, $fixture->getId()));
90+
91+
$this->client->submitForm('Update', [
92+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
93+
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Something New',
94+
<?php endforeach; ?>
95+
]);
96+
97+
self::assertResponseRedirects('<?= $route_path; ?>/');
98+
99+
$fixture = $this->repository->findAll();
100+
101+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
102+
self::assertSame('Something New', $fixture[0]->get<?= ucfirst($form_field); ?>());
103+
<?php endforeach; ?>
104+
}
105+
106+
public function testRemove(): void
107+
{
108+
$this->markTestIncomplete();
109+
$fixture = new <?= $entity_class_name; ?>();
110+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
111+
$fixture->set<?= ucfirst($form_field); ?>('Value');
112+
<?php endforeach; ?>
113+
114+
$$this->manager->remove($fixture);
115+
$this->manager->flush();
116+
117+
$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));
118+
$this->client->submitForm('Delete');
119+
120+
self::assertResponseRedirects('<?= $route_path; ?>/');
121+
self::assertSame(0, $this->repository->count([]));
122+
}
123+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?= "<?php\n" ?>
2+
<?php use Symfony\Bundle\MakerBundle\Str; ?>
3+
4+
namespace <?= $namespace ?>;
5+
6+
<?= $use_statements; ?>
7+
8+
class <?= $class_name ?> extends WebTestCase<?= "\n" ?>
9+
{
10+
<?= $use_typed_properties ? null : " /** @var KernelBrowser */\n" ?>
11+
private <?= $use_typed_properties ? 'KernelBrowser ' : null ?>$client;
12+
<?= $use_typed_properties ? null : " /** @var $repository_class_name */\n" ?>
13+
private <?= $use_typed_properties ? "$repository_class_name " : null ?>$repository;
14+
private <?= $use_typed_properties ? 'string ' : null ?>$path = '<?= $route_path; ?>/';
15+
16+
protected function setUp(): void
17+
{
18+
$this->client = static::createClient();
19+
$this->repository = (static::getContainer()->get('doctrine'))->getRepository(<?= $entity_class_name; ?>::class);
20+
21+
foreach ($this->repository->findAll() as $object) {
22+
$this->repository->remove($object, true);
23+
}
24+
}
25+
26+
public function testIndex(): void
27+
{
28+
$crawler = $this->client->request('GET', $this->path);
29+
30+
self::assertResponseStatusCodeSame(200);
31+
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?> index');
32+
33+
// Use the $crawler to perform additional assertions e.g.
34+
// self::assertSame('Some text on the page', $crawler->filter('.p')->first());
35+
}
36+
37+
public function testNew(): void
38+
{
39+
$this->markTestIncomplete();
40+
$this->client->request('GET', sprintf('%snew', $this->path));
41+
42+
self::assertResponseStatusCodeSame(200);
43+
44+
$this->client->submitForm('Save', [
45+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
46+
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Testing',
47+
<?php endforeach; ?>
48+
]);
49+
50+
self::assertResponseRedirects('/sweet/food/');
51+
52+
self::assertSame(1, $this->repository->count([]));
53+
}
54+
55+
public function testShow(): void
56+
{
57+
$this->markTestIncomplete();
58+
$fixture = new <?= $entity_class_name; ?>();
59+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
60+
$fixture->set<?= ucfirst($form_field); ?>('My Title');
61+
<?php endforeach; ?>
62+
63+
$this->repository->add($fixture, true);
64+
65+
$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));
66+
67+
self::assertResponseStatusCodeSame(200);
68+
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?>');
69+
70+
// Use assertions to check that the properties are properly displayed.
71+
}
72+
73+
public function testEdit(): void
74+
{
75+
$this->markTestIncomplete();
76+
$fixture = new <?= $entity_class_name; ?>();
77+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
78+
$fixture->set<?= ucfirst($form_field); ?>('My Title');
79+
<?php endforeach; ?>
80+
81+
$this->repository->add($fixture, true);
82+
83+
$this->client->request('GET', sprintf('%s%s/edit', $this->path, $fixture->getId()));
84+
85+
$this->client->submitForm('Update', [
86+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
87+
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Something New',
88+
<?php endforeach; ?>
89+
]);
90+
91+
self::assertResponseRedirects('<?= $route_path; ?>/');
92+
93+
$fixture = $this->repository->findAll();
94+
95+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
96+
self::assertSame('Something New', $fixture[0]->get<?= ucfirst($form_field); ?>());
97+
<?php endforeach; ?>
98+
}
99+
100+
public function testRemove(): void
101+
{
102+
$this->markTestIncomplete();
103+
$fixture = new <?= $entity_class_name; ?>();
104+
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
105+
$fixture->set<?= ucfirst($form_field); ?>('My Title');
106+
<?php endforeach; ?>
107+
108+
$this->repository->add($fixture, true);
109+
110+
$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));
111+
$this->client->submitForm('Delete');
112+
113+
self::assertResponseRedirects('<?= $route_path; ?>/');
114+
self::assertSame(0, $this->repository->count([]));
115+
}
116+
}

0 commit comments

Comments
 (0)