Skip to content

Commit

Permalink
feature #307 [make:crud][experimental] Add generated tests to make:cr…
Browse files Browse the repository at this point in the history
…ud (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
  • Loading branch information
weaverryan committed May 9, 2022
2 parents e2d6c94 + 3d9adfb commit 767be43
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 15 deletions.
49 changes: 49 additions & 0 deletions src/Maker/MakeCrud.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Inflector\InflectorFactory;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
Expand Down Expand Up @@ -46,6 +49,7 @@ final class MakeCrud extends AbstractMaker
private $formTypeRenderer;
private $inflector;
private $controllerClassName;
private $generateTests = false;

public function __construct(DoctrineHelper $doctrineHelper, FormTypeRenderer $formTypeRenderer)
{
Expand Down Expand Up @@ -95,6 +99,8 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma
sprintf('Choose a name for your controller class (e.g. <fg=yellow>%s</>)', $defaultControllerClass),
$defaultControllerClass
);

$this->generateTests = $io->confirm('Do you want to generate tests for the controller?. [Experimental]', false);
}

public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
Expand Down Expand Up @@ -232,6 +238,49 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
);
}

if ($this->generateTests) {
$testClassDetails = $generator->createClassNameDetails(
$entityClassDetails->getRelativeNameWithoutSuffix(),
'Test\\Controller\\',
'ControllerTest'
);

$useStatements = new UseStatementGenerator([
$entityClassDetails->getFullName(),
WebTestCase::class,
KernelBrowser::class,
$repositoryClassName,
]);

$usesEntityManager = EntityManagerInterface::class === $repositoryClassName;

if ($usesEntityManager) {
$useStatements->addUseStatement(EntityRepository::class);
}

$generator->generateFile(
'tests/Controller/'.$testClassDetails->getShortName().'.php',
$usesEntityManager ? 'crud/test/Test.EntityManager.tpl.php' : 'crud/test/Test.tpl.php',
[
'use_statements' => $useStatements,
'entity_full_class_name' => $entityClassDetails->getFullName(),
'entity_class_name' => $entityClassDetails->getShortName(),
'entity_var_singular' => $entityVarSingular,
'route_path' => Str::asRoutePath($controllerClassDetails->getRelativeNameWithoutSuffix()),
'route_name' => $routeName,
'class_name' => Str::getShortClassName($testClassDetails->getFullName()),
'namespace' => Str::getNamespace($testClassDetails->getFullName()),
'form_fields' => $entityDoctrineDetails->getFormFields(),
'repository_class_name' => $usesEntityManager ? EntityManagerInterface::class : $repositoryVars['repository_class_name'],
'form_field_prefix' => strtolower(Str::asSnakeCase($entityTwigVarSingular)),
]
);

if (!class_exists(WebTestCase::class)) {
$io->caution('You\'ll need to install the `symfony/test-pack` to execute the tests for your new controller.');
}
}

$generator->writeChanges();

$this->writeSuccessMessage($io);
Expand Down
123 changes: 123 additions & 0 deletions src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?= "<?php\n" ?>
<?php use Symfony\Bundle\MakerBundle\Str; ?>

namespace <?= $namespace ?>;

<?= $use_statements; ?>

class <?= $class_name ?> extends WebTestCase<?= "\n" ?>
{
<?= $use_typed_properties ? null : " /** @var KernelBrowser */\n" ?>
private <?= $use_typed_properties ? 'KernelBrowser ' : null ?>$client;
<?= $use_typed_properties ? null : " /** @var EntityManagerInterface */\n" ?>
private <?= $use_typed_properties ? 'EntityManagerInterface ' : null ?>$manager;
<?= $use_typed_properties ? null : " /** @var EntityRepository */\n" ?>
private <?= $use_typed_properties ? 'EntityRepository ' : null ?>$repository;
private <?= $use_typed_properties ? 'string ' : null ?>$path = '<?= $route_path; ?>/';

protected function setUp(): void
{
$this->client = static::createClient();
$this->manager = (static::getContainer()->get('doctrine'))->getManager();
$this->repository = $this->manager->getRepository(<?= $entity_class_name; ?>::class);

foreach ($this->repository->findAll() as $object) {
$this->manager->remove($object);
}

$this->manager->flush();
}

public function testIndex(): void
{
$crawler = $this->client->request('GET', $this->path);

self::assertResponseStatusCodeSame(200);
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?> index');

// Use the $crawler to perform additional assertions e.g.
// self::assertSame('Some text on the page', $crawler->filter('.p')->first());
}

public function testNew(): void
{
$this->markTestIncomplete();
$this->client->request('GET', sprintf('%snew', $this->path));

self::assertResponseStatusCodeSame(200);

$this->client->submitForm('Save', [
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Testing',
<?php endforeach; ?>
]);

self::assertResponseRedirects('/sweet/food/');

self::assertSame(1, $this->getRepository()->count([]));
}

public function testShow(): void
{
$this->markTestIncomplete();
$fixture = new <?= $entity_class_name; ?>();
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
$fixture->set<?= ucfirst($form_field); ?>('My Title');
<?php endforeach; ?>

$this->repository->add($fixture, true);

$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));

self::assertResponseStatusCodeSame(200);
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?>');

// Use assertions to check that the properties are properly displayed.
}

public function testEdit(): void
{
$this->markTestIncomplete();
$fixture = new <?= $entity_class_name; ?>();
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
$fixture->set<?= ucfirst($form_field); ?>('Value');
<?php endforeach; ?>

$this->manager->persist($fixture);
$this->manager->flush();

$this->client->request('GET', sprintf('%s%s/edit', $this->path, $fixture->getId()));

$this->client->submitForm('Update', [
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Something New',
<?php endforeach; ?>
]);

self::assertResponseRedirects('<?= $route_path; ?>/');

$fixture = $this->repository->findAll();

<?php foreach ($form_fields as $form_field => $typeOptions): ?>
self::assertSame('Something New', $fixture[0]->get<?= ucfirst($form_field); ?>());
<?php endforeach; ?>
}

public function testRemove(): void
{
$this->markTestIncomplete();
$fixture = new <?= $entity_class_name; ?>();
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
$fixture->set<?= ucfirst($form_field); ?>('Value');
<?php endforeach; ?>

$$this->manager->remove($fixture);
$this->manager->flush();

$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));
$this->client->submitForm('Delete');

self::assertResponseRedirects('<?= $route_path; ?>/');
self::assertSame(0, $this->repository->count([]));
}
}
116 changes: 116 additions & 0 deletions src/Resources/skeleton/crud/test/Test.tpl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?= "<?php\n" ?>
<?php use Symfony\Bundle\MakerBundle\Str; ?>

namespace <?= $namespace ?>;

<?= $use_statements; ?>

class <?= $class_name ?> extends WebTestCase<?= "\n" ?>
{
<?= $use_typed_properties ? null : " /** @var KernelBrowser */\n" ?>
private <?= $use_typed_properties ? 'KernelBrowser ' : null ?>$client;
<?= $use_typed_properties ? null : " /** @var $repository_class_name */\n" ?>
private <?= $use_typed_properties ? "$repository_class_name " : null ?>$repository;
private <?= $use_typed_properties ? 'string ' : null ?>$path = '<?= $route_path; ?>/';

protected function setUp(): void
{
$this->client = static::createClient();
$this->repository = (static::getContainer()->get('doctrine'))->getRepository(<?= $entity_class_name; ?>::class);

foreach ($this->repository->findAll() as $object) {
$this->repository->remove($object, true);
}
}

public function testIndex(): void
{
$crawler = $this->client->request('GET', $this->path);

self::assertResponseStatusCodeSame(200);
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?> index');

// Use the $crawler to perform additional assertions e.g.
// self::assertSame('Some text on the page', $crawler->filter('.p')->first());
}

public function testNew(): void
{
$this->markTestIncomplete();
$this->client->request('GET', sprintf('%snew', $this->path));

self::assertResponseStatusCodeSame(200);

$this->client->submitForm('Save', [
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Testing',
<?php endforeach; ?>
]);

self::assertResponseRedirects('/sweet/food/');

self::assertSame(1, $this->repository->count([]));
}

public function testShow(): void
{
$this->markTestIncomplete();
$fixture = new <?= $entity_class_name; ?>();
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
$fixture->set<?= ucfirst($form_field); ?>('My Title');
<?php endforeach; ?>

$this->repository->add($fixture, true);

$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));

self::assertResponseStatusCodeSame(200);
self::assertPageTitleContains('<?= ucfirst($entity_var_singular); ?>');

// Use assertions to check that the properties are properly displayed.
}

public function testEdit(): void
{
$this->markTestIncomplete();
$fixture = new <?= $entity_class_name; ?>();
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
$fixture->set<?= ucfirst($form_field); ?>('My Title');
<?php endforeach; ?>

$this->repository->add($fixture, true);

$this->client->request('GET', sprintf('%s%s/edit', $this->path, $fixture->getId()));

$this->client->submitForm('Update', [
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
'<?= $form_field_prefix; ?>[<?= $form_field; ?>]' => 'Something New',
<?php endforeach; ?>
]);

self::assertResponseRedirects('<?= $route_path; ?>/');

$fixture = $this->repository->findAll();

<?php foreach ($form_fields as $form_field => $typeOptions): ?>
self::assertSame('Something New', $fixture[0]->get<?= ucfirst($form_field); ?>());
<?php endforeach; ?>
}

public function testRemove(): void
{
$this->markTestIncomplete();
$fixture = new <?= $entity_class_name; ?>();
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
$fixture->set<?= ucfirst($form_field); ?>('My Title');
<?php endforeach; ?>

$this->repository->add($fixture, true);

$this->client->request('GET', sprintf('%s%s', $this->path, $fixture->getId()));
$this->client->submitForm('Delete');

self::assertResponseRedirects('<?= $route_path; ?>/');
self::assertSame(0, $this->repository->count([]));
}
}
Loading

0 comments on commit 767be43

Please sign in to comment.