Skip to content

[PHPUnit] Safe way to check if a class is a Test class#374

Merged
TomasVotruba merged 5 commits intomasterfrom
phpunit
Apr 1, 2018
Merged

[PHPUnit] Safe way to check if a class is a Test class#374
TomasVotruba merged 5 commits intomasterfrom
phpunit

Conversation

@carusogabriel
Copy link
Copy Markdown
Contributor

@carusogabriel carusogabriel commented Mar 20, 2018

The current logic checks if the TestCase ends with Test, but this isn't the safest way to do it. For example:

<?php
class TestingCase extends \PHPUnit\Framework\TestCase {}

class MyTestCase extends TestingCase {}

@carusogabriel carusogabriel self-assigned this Mar 20, 2018
@carusogabriel carusogabriel changed the title [PHPUnit] Safe way to check if a class is a Test class [WIP][PHPUnit] Safe way to check if a class is a Test class Mar 20, 2018
@carusogabriel
Copy link
Copy Markdown
Contributor Author

Do not merge wet, some cases fail if the test class extends a class that actually extends PHPUnit. I'll add tests to ensure that.

Comment thread src/Rector/AbstractPHPUnitRector.php Outdated
protected function isInTestClass(Node $node): bool
{
$className = (string) $node->getAttribute(Attribute::CLASS_NAME);
$parentClassName = (string) $node->getAttribute(Attribute::PARENT_CLASS_NAME);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomasVotruba Do you know any Attribute that indicates all class parents?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All available Attribute items are in the Attribute class.

This should be resolved by TypeResolver, as it's used only sometimes. So I'd get CLASS_NODE and then get its types.

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomasVotruba Do you have an example of TypeResolver that I can study and update this PR?

Comment thread src/Rector/AbstractPHPUnitRector.php Outdated
protected function isInTestClass(Node $node): bool
{
$className = (string) $node->getAttribute(Attribute::CLASS_NAME);
$parentClassName = (string) $node->getAttribute(Attribute::PARENT_CLASS_NAME);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All available Attribute items are in the Attribute class.

This should be resolved by TypeResolver, as it's used only sometimes. So I'd get CLASS_NODE and then get its types.

What do you think?

* Check if the file is a PHPUnit TestCase. By default, it should end with "Test", as it is the standard.
*
* @see https://phpunit.de/getting-started-with-phpunit.html
*/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removing this?

What if sb will come and try to analyze nodes (much worse performance) instead of simple and fast PHPUnit approach.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I test Rector against an application that didn't follow this rule, plus, all its test classes extends a based one :(

Copy link
Copy Markdown
Member

@TomasVotruba TomasVotruba Mar 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.

Failing test would tell this for itself. What about that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/Rector/AbstractPHPUnitRector.php Outdated
protected function isInTestClass(Node $node): bool
{
$className = (string) $node->getAttribute(Attribute::CLASS_NAME);
$nodeTypeResolver = new NodeTypeResolver();
Copy link
Copy Markdown
Contributor Author

@carusogabriel carusogabriel Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomasVotruba Should we revert #300? Because doing this way, isn't working by our CS :(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TomasVotruba ping.

Is there a way to DI without __construct? If not, revert #300 will be the solution (unfortunately)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this, sorry.

You can inject dependency as in Abstract class:

/**
* @var ExpressionAdder
*/
private $expressionAdder;
/**
* @var PropertyAdder
*/
private $propertyAdder;
/**
* Nasty magic, unable to do that in config autowire _instanceof calls.
*
* @required
*/
public function setExpressionAdder(ExpressionAdder $expressionAdder): void
{
$this->expressionAdder = $expressionAdder;
}
/**
* Nasty magic, unable to do that in config autowire _instanceof calls.
*
* @required
*/
public function setPropertyToClassAdder(PropertyAdder $propertyAdder): void
{
$this->propertyAdder = $propertyAdder;
}

That's Symfony approach to this

@carusogabriel carusogabriel changed the title [WIP][PHPUnit] Safe way to check if a class is a Test class [PHPUnit] Safe way to check if a class is a Test class Mar 31, 2018
@carusogabriel
Copy link
Copy Markdown
Contributor Author

Finally done, we can now merge it 🎉

Copy link
Copy Markdown
Member

@TomasVotruba TomasVotruba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one detail and it's ready to merge

Comment thread src/Rector/AbstractPHPUnitRector.php Outdated
$nodeResolved = $this->nodeTypeResolver->resolve($node);

return Strings::endsWith($className, 'Test');
return ! array_intersect([TestCase::class, 'PHPUnit_Framework_TestCase'], $nodeResolved);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens, if sb installs a Rector but doesn't have PHPUnit with TestCase class installed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn’t get it :(

Without TestCase isn’t possible to execute tests, is?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, somebody can use PHPUnit_Framework_TestCase, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are checking it, aren't we? 🤔

return ! array_intersect([TestCase::class, 'PHPUnit_Framework_TestCase'], $nodeResolved);

Copy link
Copy Markdown
Member

@TomasVotruba TomasVotruba Mar 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but that depends on PHPUnit\Framework\TestCase class to exist. And it does in our code so it works.

Sb might download Rector and have only PHPUnit_Framework_TestCase in their code.
So PHPUnit\FrameworkTestCase will end up as un-existing class error.

That's why it should string here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I'll ignore this file from our CS. I used ::class here because CS complained about it

@TomasVotruba
Copy link
Copy Markdown
Member

Awesome, thank you 👍

@TomasVotruba TomasVotruba merged commit c7b5b67 into master Apr 1, 2018
@TomasVotruba TomasVotruba deleted the phpunit branch April 1, 2018 22:59
TomasVotruba added a commit that referenced this pull request Jul 4, 2021
echo511 pushed a commit to echo511/rector that referenced this pull request Sep 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants