├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src
├── IgnoreTestPolicy.php
└── TestListener.php
└── tests
└── TestListenerTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | composer.phar
3 | bin/
4 | vendor/
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | sudo: false
4 |
5 | cache:
6 | directories:
7 | - $HOME/.composer
8 |
9 | before_script:
10 | - phpenv config-rm xdebug.ini || true
11 | - composer self-update
12 | - composer require phpunit/phpunit:${PHPUNIT}
13 |
14 | script:
15 | - ./bin/phpunit
16 |
17 | matrix:
18 | include:
19 | - php: 7.1
20 | env: PHPUNIT=~7
21 | - php: 7.2
22 | env: PHPUNIT=~7
23 | - php: nightly
24 | env: PHPUNIT=~7
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2017 MyBuilder Limited
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHPUnit Accelerator
2 |
3 | [](http://travis-ci.org/mybuilder/phpunit-accelerator)
4 |
5 | Inspired by [Kris Wallsmith faster PHPUnit article](http://kriswallsmith.net/post/18029585104/faster-phpunit), we've created a [PHPUnit](http://phpunit.de) test listener that speeds up PHPUnit tests about 20% by freeing memory.
6 |
7 | ## Installation
8 |
9 | To install this library, run the command below and you will get the latest version
10 |
11 | ``` bash
12 | composer require mybuilder/phpunit-accelerator --dev
13 | ```
14 |
15 | ## Usage
16 |
17 | Just add to your `phpunit.xml` configuration
18 |
19 | ```xml
20 |
21 |
22 |
23 |
24 |
25 | ```
26 |
27 | ### Ignoring Tests
28 |
29 | Sometimes it is necessary to ignore specific tests, where freeing their properties is undesired. For this use case, you have the ability to *extend the behaviour* of the listener by implementing the `IgnoreTestPolicy` interface.
30 |
31 | As an example, if we hypothetically wanted to ignore all tests which include "Legacy" in their test filename, we could create a custom ignore policy as follows
32 |
33 | ```php
34 | getFilename(), 'Legacy') !== false;
41 | }
42 | }
43 | ```
44 |
45 | And pass it to the constructor of our test listener in `phpunit.xml` configuration
46 |
47 | ```xml
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ```
58 |
59 | ---
60 |
61 | Created by [MyBuilder](http://www.mybuilder.com/) - Check out our [blog](http://tech.mybuilder.com/) for more insight into this and other open-source projects we release.
62 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mybuilder/phpunit-accelerator",
3 | "description": "PHPUnit accelerator",
4 | "keywords": ["phpunit", "accelerator", "memory", "property", "free", "fast"],
5 | "license": "MIT",
6 | "minimum-stability": "stable",
7 | "authors": [
8 | {
9 | "name": "Keyvan Akbary",
10 | "email": "keyvan@mybuilder.com"
11 | }
12 | ],
13 | "require": {
14 | "php": ">=7.1",
15 | "phpunit/phpunit": ">=7.0 <8"
16 | },
17 | "autoload": {
18 | "psr-4": { "MyBuilder\\PhpunitAccelerator\\": "src" }
19 | },
20 | "config": {
21 | "bin-dir": "bin"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
15 |
16 |
17 |
18 | ./tests
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/IgnoreTestPolicy.php:
--------------------------------------------------------------------------------
1 | ignorePolicy = ($ignorePolicy) ?: new NeverIgnoreTestPolicy();
19 | }
20 |
21 | public function endTest(\PHPUnit\Framework\Test $test, float $time): void
22 | {
23 | $testReflection = new \ReflectionObject($test);
24 |
25 | if ($this->ignorePolicy->shouldIgnore($testReflection)) {
26 | return;
27 | }
28 |
29 | $this->safelyFreeProperties($test, $testReflection->getProperties());
30 | }
31 |
32 | private function safelyFreeProperties(\PHPUnit\Framework\Test $test, array $properties)
33 | {
34 | foreach ($properties as $property) {
35 | if ($this->isSafeToFreeProperty($property)) {
36 | $this->freeProperty($test, $property);
37 | }
38 | }
39 | }
40 |
41 | private function isSafeToFreeProperty(\ReflectionProperty $property)
42 | {
43 | return !$property->isStatic() && $this->isNotPhpUnitProperty($property);
44 | }
45 |
46 | private function isNotPhpUnitProperty(\ReflectionProperty $property)
47 | {
48 | return 0 !== strpos($property->getDeclaringClass()->getName(), self::PHPUNIT_PROPERTY_PREFIX);
49 | }
50 |
51 | private function freeProperty(\PHPUnit\Framework\Test $test, \ReflectionProperty $property)
52 | {
53 | $property->setAccessible(true);
54 | $property->setValue($test, null);
55 | }
56 | }
57 |
58 | class NeverIgnoreTestPolicy implements IgnoreTestPolicy
59 | {
60 | public function shouldIgnore(\ReflectionObject $testReflection)
61 | {
62 | return false;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/TestListenerTest.php:
--------------------------------------------------------------------------------
1 | dummyTest = new DummyTest();
13 | }
14 |
15 | /**
16 | * @test
17 | */
18 | public function shouldFreeTestProperty()
19 | {
20 | $this->endTest(new TestListener());
21 |
22 | $this->assertFreesTestProperty();
23 | }
24 |
25 | private function endTest(TestListener $listener)
26 | {
27 | $listener->endTest($this->dummyTest, 0);
28 | }
29 |
30 | private function assertFreesTestProperty()
31 | {
32 | $this->assertNull($this->dummyTest->property);
33 | }
34 |
35 | /**
36 | * @test
37 | */
38 | public function shouldNotFreePhpUnitProperty()
39 | {
40 | $this->endTest(new TestListener());
41 |
42 | $this->assertDoesNotFreePHPUnitProperty();
43 | }
44 |
45 | private function assertDoesNotFreePHPUnitProperty()
46 | {
47 | $this->assertNotNull($this->dummyTest->phpUnitProperty);
48 | }
49 |
50 | /**
51 | * @test
52 | */
53 | public function shouldNotFreeTestPropertyWithIgnoreAlwaysPolicy()
54 | {
55 | $this->endTest(new TestListener(new AlwaysIgnoreTestPolicy()));
56 |
57 | $this->assertDoesNotFreeTestProperty();
58 | }
59 |
60 | private function assertDoesNotFreeTestProperty()
61 | {
62 | $this->assertNotNull($this->dummyTest->property);
63 | }
64 | }
65 |
66 | class PHPUnit_Fake extends \PHPUnit\Framework\TestCase
67 | {
68 | public $phpUnitProperty = 1;
69 | }
70 |
71 | class DummyTest extends \PHPUnit_Fake
72 | {
73 | public $property = 1;
74 | }
75 |
76 | class AlwaysIgnoreTestPolicy implements IgnoreTestPolicy
77 | {
78 | public function shouldIgnore(\ReflectionObject $testReflection)
79 | {
80 | return true;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------