# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.labrador-kennel.io/async-unit/tutorials/testcase-hooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
