Skip to content

Commit

Permalink
Atomize TestMethodPass.
Browse files Browse the repository at this point in the history
  • Loading branch information
adamelso committed Jun 10, 2024
1 parent d9a7de2 commit c251662
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 81 deletions.
1 change: 1 addition & 0 deletions lib/Transunit/Pass.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ interface Pass
{
/** @param Node[] $ast */
public function find(NodeFinder $nodeFinder, $ast): array;

public function rewrite(Node $node): void;
}
54 changes: 54 additions & 0 deletions lib/Transunit/Pass/AddTestMethodPrefixPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Transunit\Pass;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\NodeFinder;
use Transunit\Pass;

/**
* ```
* - function it_handles_kernel_request_events()
* + public function test_it_handles_kernel_request_events(): void
* {
* ```
*/
class AddTestMethodPrefixPass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
{
return $nodeFinder->find($ast, function (Node $node) {
if ($node instanceof Node\Stmt\ClassMethod && !in_array($node->name->toString(), ['setUp', 'let'],true)) {
return $node;
}

return null;
});
}

public function rewrite(Node $node): void
{
if (!$node instanceof Node\Stmt\ClassMethod) {
return;
}

$this->addPrefix($node);
}

/**
* public function test_it_should_do_something(): void { ... }
*/
private function addPrefix(Node\Stmt\ClassMethod $node): void
{
$methodName = $node->name->toString();

if (0 !== strpos($methodName, 'it_')) {
return;
}

$node->name = new Node\Identifier('test_' . $methodName);
$node->flags = Modifiers::PUBLIC;
$node->returnType = new Node\Name('void');
}
}
6 changes: 6 additions & 0 deletions lib/Transunit/Pass/AssertionPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
use PhpParser\Node;
use Transunit\Pass;

/**
* ```
* - $this->_testSubject->contractOut(47)->shouldReturn($agent47);
* + static::assertSame($agent47, $this->_testSubject->contractOut(47));
* ```
*/
class AssertionPass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
Expand Down
12 changes: 12 additions & 0 deletions lib/Transunit/Pass/CallTestSubjectPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
use PhpParser\NodeFinder;
use Transunit\Pass;

/**
* ```
* function it_contracts_out_agents(AgentRepository $agentRepository, EventDispatcher $eventDispatcher, Agent $agent47, ContractEvent $event)
* {
* $this->agentRepository->find(47)->willReturn($agent47);
* $this->eventDispatcher->dispatch($event)->shouldBeCalled();
*
* - $this->contractOut(47)->shouldReturn($agent47);
* + $this->_testSubject->contractOut(47)->shouldReturn($agent47);
* }
* ```
*/
class CallTestSubjectPass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
Expand Down
26 changes: 26 additions & 0 deletions lib/Transunit/Pass/GlobalCollaboratorPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,32 @@
use PhpParser\NodeFinder;
use Transunit\Pass;

/**
* ```
* class TestSubjectTest extends TestCase
* {
* use ProphecyTrait;
*
* + private ObjectProphecy|AgentRepository $agentRepository;
* + private ObjectProphecy|EventDispatcher $eventDispatcher;
*
* function let(AgentRepository $agentRepository, EventDispatcher $eventDispatcher)
* {
* $this->beConstructedWith($agentRepository, $eventDispatcher);
* }
*
* function it_contracts_out_agents(AgentRepository $agentRepository, EventDispatcher $eventDispatcher, Agent $agent47, ContractEvent $event)
* {
* - $agentRepository->find(47)->willReturn($agent47);
* + $this->agentRepository->find(47)->willReturn($agent47);
*
* - $eventDispatcher->dispatch($event)->shouldBeCalled();
* + $this->eventDispatcher->dispatch($event)->shouldBeCalled();
*
* $this->contractOut(47)->shouldReturn($agent47);
* }
* ```
*/
class GlobalCollaboratorPass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
Expand Down
16 changes: 16 additions & 0 deletions lib/Transunit/Pass/GlobalTestSubjectInstancePass.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@
use PhpParser\NodeFinder;
use Transunit\Pass;

/**
* ```
* class TestSubjectTest extends TestCase
* {
* use ProphecyTrait;
*
* + private TestSubject $_testSubject;
*
* - function let(AgentRepository $agentRepository, EventDispatcher $eventDispatcher)
* + protected function setUp(): void
* {
* - $this->beConstructedWith($agentRepository, $eventDispatcher);
* + $this->_testSubject = new TestSubject($this->agentRepository->reveal(), $this->eventDispatcher->reveal());
* }
* ```
*/
class GlobalTestSubjectInstancePass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
Expand Down
86 changes: 86 additions & 0 deletions lib/Transunit/Pass/ProphesizeGlobalCollaboratorsPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Transunit\Pass;

use PhpParser\Node;
use PhpParser\NodeFinder;
use Transunit\Pass;

/**
* ```
* - protected function setUp(AgentRepository $agentRepository, EventDispatcher $eventDispatcher): void
* + protected function setUp(): void
* {
* + $this->agentRepository = $this->prophesize(AgentRepository::class);
* + $this->eventDispatcher = $this->prophesize(EventDispatcher::class);
*
* // ...
* }
* ```
*/
class ProphesizeGlobalCollaboratorsPass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
{
return $nodeFinder->find($ast, function (Node $node) {
if ($node instanceof Node\Stmt\ClassMethod && !in_array($node->name->toString(), ['setUp', 'let'],true)) {
return $node;
}

return null;
});
}

public function rewrite(Node $node): void
{
if (!$node instanceof Node\Stmt\ClassMethod) {
return;
}

$this->prophesizeGlobalCollaborators($node);
}

/**
* protected function setUp(): void {
* $this->classCollaborator = $this->prophesize(ClassCollaborator::class);
* }
*/
private function prophesizeGlobalCollaborators(Node\Stmt\ClassMethod $node): void
{
if (!in_array($node->name->toString(), ['let', 'setUp'], true)) {
return;
}

$newStmts = [];

while (count($node->params) > 0) {
$param = array_pop($node->params);

$newStmts[] = new Node\Stmt\Expression(
new Node\Expr\Assign(
// assign class property
new Node\Expr\PropertyFetch(
new Node\Expr\Variable('this'),
$param->var->name
),
new Node\Expr\MethodCall(
new Node\Expr\Variable('this'),
'prophesize',
[
new Node\Arg(new Node\Expr\ClassConstFetch(
new Node\Name($param->type->toString()),
'class'
)),
]
)
)
);

foreach ($node->stmts as $currentStmt) {
$newStmts[] = $currentStmt;
}
}

$node->stmts = $newStmts;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,23 @@

namespace Transunit\Pass;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\NodeFinder;
use Transunit\Pass;

class TestMethodPass implements Pass
/**
* ```
* - public function test_it_handles_events(Event $event): void
* + public function test_it_handles_events(): void
* {
* + $event = $this->prophesize(Event::class);
*
* - $this->_testSubject->onKernelRequest($event);
* + $this->_testSubject->onKernelRequest($event->reveal());
* }
* ```
*/
class ProphesizeLocalCollaboratorsPass implements Pass
{
public function find(NodeFinder $nodeFinder, $ast): array
{
Expand All @@ -26,85 +37,9 @@ public function rewrite(Node $node): void
return;
}

$this->renameSetup($node);
$this->addPrefix($node);
$this->prophesizeGlobalCollaborators($node);
$this->prophesizeLocalCollaborators($node);
}

/**
* public function test_it_should_do_something(): void { ... }
*/
private function addPrefix(Node\Stmt\ClassMethod $node): void
{
$methodName = $node->name->toString();

if (0 !== strpos($methodName, 'it_')) {
return;
}

$node->name = new Node\Identifier('test_' . $methodName);
$node->flags = Modifiers::PUBLIC;
$node->returnType = new Node\Name('void');
}

/**
* protected function setUp(): void { ... }
*/
private function renameSetup(Node\Stmt\ClassMethod $node): void
{
if ($node->name->toString() !== 'let') {
return;
}

$node->name = new Node\Identifier('setUp');
$node->flags = Modifiers::PROTECTED;
}

/**
* protected function setUp(): void {
* $this->classCollaborator = $this->prophesize(ClassCollaborator::class);
* }
*/
private function prophesizeGlobalCollaborators(Node\Stmt\ClassMethod $node): void
{
if (!in_array($node->name->toString(), ['let', 'setUp'], true)) {
return;
}

$newStmts = [];

while (count($node->params) > 0) {
$param = array_pop($node->params);

$newStmts[] = new Node\Stmt\Expression(
new Node\Expr\Assign(
// assign class property
new Node\Expr\PropertyFetch(
new Node\Expr\Variable('this'),
$param->var->name
),
new Node\Expr\MethodCall(
new Node\Expr\Variable('this'),
'prophesize',
[
new Node\Arg(new Node\Expr\ClassConstFetch(
new Node\Name($param->type->toString()),
'class'
)),
]
)
)
);

foreach ($node->stmts as $currentStmt) {
$newStmts[] = $currentStmt;
}
}

$node->stmts = $newStmts;
}

/**
* public function test_it_should_do_something(): void {
* $methodCollaborator = $this->prophesize(MethodCollaborator::class);
Expand Down
Loading

0 comments on commit c251662

Please sign in to comment.