PHPUnit: How do I create a function to be called once for all the tests in a class?

PhpPhpunit

Php Problem Overview


I have a PHPUnit test case class (consisting of some test functions). I would like to write a oneTimeSetUp() function to be called once for all my tests in the class (unlike the standard setUp() function which is called once for each test in the class). In other words, I'm looking for a PHPUnit equivalent to the JUnit @BeforeClass annotation.

Same question with a oneTimeTearDown() function.

Is it possible to do so in PHPUnit?

Php Solutions


Solution 1 - Php

Take a look at setUpBeforeClass() from section 6 of the PHPUnit documentation.

For the one time tearDown you should use tearDownAfterClass();.

Both this methods should be defined in your class as static methods.

Solution 2 - Php

setUpBeforeClass() is the way to do this if all of your tests are literally contained within a single class.

However, your question sort of implies that you may be using your test class as a base class for multiple test classes. In that case setUpBeforeClass will be run before each one. If you only want to run it once you could guard it with a static variable:

abstract class TestBase extends TestCase {

  protected static $initialized = FALSE;
  
  public function setUp() {
    
    parent::setUp();

    if (!self::$initialized) {
      // Do something once here for _all_ test subclasses.
      self::$initialized = TRUE;
    }
  }

}

A final option might be a test listener.

Solution 3 - Php

I came to this page with the same question, however the accepted answer is ran on all classes, and for me was not the correct answer.

If you are like me, your first "Integration test" is to clear out the DB, and run migrations. This gets yourself at a database baseline for all test. I am constantly changing migration files at this point, so setting up the baseline is truly part of all tests.

The migration takes a while, so I do not want it run on all tests.

Then I needed to build up the database testing each piece. I need to write an order test, but first I need to create some products and test that, then I need to test an import fuction.

So, what I did is SUPER easy, but not explained extremely well on the internet. I created a simple test to setup the database. Then in your phpspec.xml file add a testsuite....

<testsuite name="Products">
    <file>tests/in/SystemSetupTest.php</file>
    <file>tests/in/ProductTest.php</file>
    <file>tests/in/ProductImportTest.php</file>
</testsuite>

And in the the SystemSetupTest.php ....

class SystemSetupTest extends ApiTester
{

    /** @test */
    function system_init()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        self::createEM(); //this has all the code to init the system...
    }
}

Then execute it like:

phpunit --testsuite Products

In the end, its a ton easier. It will allow me to build up my system correctly.

Additionally I am using laravel 5. When using setUpBeforeClass() I end up with bootstrap issues, which I am sure I can fix, but the method I use above works perfect.

Solution 4 - Php

The bootstrap option can be used on these cases.

You can call it from the command line

phpunit --bootstrap myBootstrap.php

Or put it in the XML file, like this:

<phpunit bootstrap="myBootstrap.php">
...
</phpunit>

Solution 5 - Php

Expanding on accepted answer:

None of the setUpBeforeClass(), tearDownAfterClass(), @beforeClass, @afterClass runs in the object context (static methods). You can work around that restriction by guarding any @before code with a static property instead, like so:

class MyTest extends PHPUnit\Framework\TestCase
{
    private static $ready = false;

    /**
     * @before
     */
    protected function firstSetUp()
    {
        if (static::$ready))
            return;

        /* your one time setUp here */

        static::$ready = true;
    }
}

It can't be used for @after, however, because there's no way of saying when the last test was called.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsnakileView Question on Stackoverflow
Solution 1 - PhpborribleView Answer on Stackoverflow
Solution 2 - PhpDane PowellView Answer on Stackoverflow
Solution 3 - PhpIannazziView Answer on Stackoverflow
Solution 4 - PhpGus CostaView Answer on Stackoverflow
Solution 5 - PhpcprnView Answer on Stackoverflow