> For the complete documentation index, see [llms.txt](https://docs.labrador-kennel.io/async-unit/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.labrador-kennel.io/async-unit/tutorials/testcase-hooks.md).

# TestCase Hooks

In any reasonably complex test suite there's going to come a need to perform some scaffolding or test setup and ensure that everything has been torn back down. AsyncUnit takes care of this with a series of Attributes annotated on public methods of the TestCase that are called *hooks*. These methods can perform any scaffolding or tear down that might be needed.

{% hint style="info" %}
TestCase hooks are only invoked if they are defined on the TestCase being tested. Hooks defined on parent TestCases are **NOT** implicitly invoked and must be called yourself.
{% endhint %}

### Setup for each test

If you've gotten to this framework then surely you've heard of the awesome [PHPUnit](https://phpunit.de/)? If not, you should absolutely go check it out before you do anything else! After you've done so then you'll be nodding along with the rest of us when I talk about `setUp` and `tearDown`, a concept PHPUnit refers to as a "fixture". These two work-horse methods get the brunt of the test scaffolding work. In AsyncUnit instead of methods with specific names we look for a public method annotated with `#[BeforeEach]` and `#[AfterEach]` , respectively.

If you wanted to follow PHPUnit's nomenclature we'd implement a TestCase like the following.

```php
<?php

use Cspray\Labrador\AsyncUnit\Attribute\BeforeEach;
use Cspray\Labrador\AsyncUnit\Attribute\Test;
use Cspray\Labrador\AsyncUnit\Attribute\AfterEach;

class MyTestCase extends TestCase {

    private string $bestFramework;

    #[BeforeEach]
    public function setUp() {
        $this->bestFramework = 'AsyncUnit';
    }
    
    #[Test]
    public function whosTheBest() {
        $this->assert()->stringEquals('AsyncUnit', $this->bestFramework);
    }
    
    #[AfterEach]
    public function tearDown() {
        $this->bestFramework = null;
    }
    
}
```

That's all there is to it! The actual method names that we used here don't actually matter and can be whatever you want; these names were chosen for their familiarity with PHPUnit. Generally we'd advise you to have more semantic names that describe what your setup is actually doing.

### TestCase wide setup and tear down

Sometimes you might need to do something that should be done once for all of the tests in a `TestCase`. Again, using PHPUnit as an example, this would correlate to `setUpBeforeClass` and `tearDownAfterClass`. It is important to note that this method must be static.

```php
<?php

use Cspray\Labrador\AsyncUnit\TestCase;
use Cspray\Labrador\AsyncUnit\Attribute\Test;
use Cspray\Labrador\AsyncUnit\Attribute\BeforeAll;
use Cspray\Labrador\AsyncUnit\Attribute\AfterAll;

class MyTestCase extends TestCase {

    private static string $subject;

    #[BeforeAll]
    public static function setUpBeforeClass() {
        self::$subject = 'AsyncUnit';
    }
    
    #[Test]
    public function ensureStaticValueSet() {
        $this->assert()->stringEquals('AsyncUnit', 'AsyncUnit');
    }

    #[AfterAll]
    public static function tearDownAfterClass() {
        self::$subject = null;
    }
}
```

That is all of the hooks available to a TestCase. These help ensure that tests can be setup and torn down correctly. There are no technical limits on the number of hooks. However, we advise generally having 1 hook or as minimum a number as possible to keep the cognitive overhead low.

{% hint style="warning" %}

#### When Multiple Hooks are Defined

There is currently a limitation in the framework, due to the nature of the underlying libraries used, where multiple TestCase hooks are invoked in a non-deterministic order. Future versions will include the ability to define a specific order in which test case hooks should be invoked.
{% endhint %}
