Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix static hooks #357

Merged
merged 5 commits into from
Jul 26, 2021
Merged

Fix static hooks #357

merged 5 commits into from
Jul 26, 2021

Conversation

jordanbrauer
Copy link
Contributor

@jordanbrauer jordanbrauer commented Jul 22, 2021

Q A
Bug fix? yes
New feature? no
Fixed tickets #351

Issue

The issue is essentially, exactly, as described by @fnzr in the related ticket (great job and good find!).

Basically, the problem happens because each test, when it's being parsed, registers the global hook on a shared variable (Testable::$beforeAll) as if it were a new hook. The solution would be...well, not do that. [...]

More specifically it is a result of the static nature of these hooks, which is why we do not see this behaviour on the beforeEach and afterEach variants. This would have been a huge oversight on my part when initially implementing this feature in #282 , and could pose a potential performance issue for some folks, should they be doing any heavy work or network activity within.

Solution

Funnily enough, it's a one-liner ... 😑 ... 🤣 . Nearly all changes are test related.

Source

  • ensure that we re-initialize static ?Closure $beforeAll and static ?Closure $afterAll at constructor-time for each test case, within the Testable concern trait;

Tests

Due to how these hooks work (e.g., can be defined in multiple files, variable amount of tests using them, etc.), it's a little tricky to ensure they are only run once per file. The solution to this is outlined below.

  • add a calls property to the global $globalHook object;
    • within here we keep a running total of hook calls, starting at 0;
  • within each hook (we are testing), assert & increment it's call count;
    • call count is always incremented by 1, except in the tests themselves;
    • when asserting the call count, depending on the test we need to calculate and apply a delta/offset to our expected value;

in other words, they can only run once per file
this happens due to the global `*All()` hooks (before & after) being
defined as static. We should be a good citizen and we need to clean up
our mess for the next person in the test instance constructor
@jordanbrauer jordanbrauer marked this pull request as ready for review July 22, 2021 02:20
@jordanbrauer
Copy link
Contributor Author

CC @nunomaduro @owenvoke @lukeraymonddowning

Requesting a review for this bug fix when you find some time 🙂

@@ -73,6 +73,7 @@ public function __construct(Closure $test, string $description, array $data)
{
$this->__test = $test;
$this->__description = $description;
self::$beforeAll = self::$afterAll = null;
Copy link
Member

Choose a reason for hiding this comment

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

I know this is ripe coming from the guy who promotes higher order expectations inside higher order tests but should we split this over two lines for clarity?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably, yeah. It is kind of easy to miss, if not careful. Two lines it is!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated!

@lukeraymonddowning
Copy link
Member

@jordanbrauer just for my own understanding, if we add another test to the AfterEachHook test down the line, we'll need to update the BeforeEachHook test offset, yes?

@jordanbrauer
Copy link
Contributor Author

if we add another test to the AfterEachHook test down the line, we'll need to update the BeforeEachHook test offset, yes?

@lukeraymonddowning , not quite, and thank goodness haha. The offset would only need to be updated if another test file was added to the tests/Hooks/ directory.

For a better visual of why offset is 2,

tests/Hooks
├── AfterAllTest.php           <-- no tests run before this one, so no offset
├── AfterEachTest.php          <-- 2 is our offset for the hook calls count
├── BeforeAllTest.php          <-- two tests run before this one
└── BeforeEachTest.php

This kind of sucks though still, because if we ever have a feature to randomize the test order (or if we currently do), it would fail for false positive. However, that being said, shouldn't be a problem since there are snapshot tests that indirectly care about the order.

Here I added some dummy tests that just expect true, but no changes to offset.

image

@nunomaduro nunomaduro merged commit f56556e into pestphp:master Jul 26, 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.

3 participants