> 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/getting-started.md).

# Getting Started

### Installation

[Composer](https://getcomposer.org/) is the only supported method for installing Labrador AsyncUnit.

```
composer require --dev cspray/labrador-async-unit
```

### Composer Autoload

It is important that tests, as well as the code being tested, are autoloaded using Composer's `./vendor/autoload.php` bootstrapping file. The framework does not include any code; a configured autoloader should handle including appropriate classes, functions, and constants that tests and code under test might use. Fortunately, Composer makes this pretty easy to do... [check out the documentation on Composer autoloading](https://getcomposer.org/doc/04-schema.md#autoload).

### Getting Started

A TestCase is an abstract class that you extend and add *tests* to *assert* that code behaves as expected. Tests are public methods on the TestCase that have been annotated with the `#[Test]` [Attribute](https://www.php.net/manual/en/language.attributes.php). The TestCase provides methods that access the Assertion API. A minimally working example, that compares 2 strings, would look something like the following...

```php
<?php

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

class MyTestCase extends TestCase {

    #[Test]
    public function nameAnAsyncTestingFramework() {
        $this-assert()->stringEquals('AsyncUnit', 'AsyncUnit');
    }

}
```

That's it! The framework comes bundled with a CLI tool that allows running tests from the command line. Assuming that this file was in a directory called `tests` the following command would process `MyTestCase`:

```bash
vendor/bin/asyncunit run tests
```

You could expect to see output like the following:

![Test output when you're all green!](/files/-MZdxFCxhtRCQYZ4DhmR)

### Hey! What about async?

Don't worry, we've got async covered! Our philosophy of treating async as a first-class citizen extends to the Assertion API as well. Let's imagine we have a method called `getAsyncIo() : Promise<string>` that we want to test.

```php
<?php

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

class MyAsyncTestCase extends TestCase {

    #[Test]
    public function ensureAsyncIoReturnsCorrectValue() {
        yield $this->asyncAssert()->stringEquals('AsyncUnit', getAsyncIo());    
    }
}
```

Pretty simple, huh? Our test becomes a generator that is automatically resolved by the testing framework. Also, notice that we pass the Promise directly to the 2nd argument of `stringEquals()`. This will be resolved by the framework and the resolved value will be what is tested against!

### Asserting not conditions

A sufficiently complex set of tests will eventually have the need to assert that something under test is *not* some value or output. The Assertion API makes this simple for all possible assertions... even custom assertions not provided out-of-the-box! This is accomplished by chaining `not()` onto `assert()` and `asyncAssert()` calls. Let's write a TestCase where we'll ensure that two strings are *not* equal to one another.

```php
<?php

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

class MyTestCase extends TestCase {

    #[Test]
    public function ensureStringsNotEqual() {
         $this->assert()->not()->stringEquals('AsyncUnit', 'PHPUnit');   
    }

}
```

That's it! This test passes as expected. If you were to make both of the strings equal to one another this test would start failing.

### The Stipulations

For the most part, that's it! There's a wealth of functionality built around the TestCase but to get up and going this is all that's required. However, there are a couple expectations before getting started.

**We expect that...**

* A `TestCase` will have at least one public method annotated with `#[Test]`. A `TestCase` without a properly annotated method will result in an error thrown during compilation.
* A `#[Test]` that does not *assert* something, either synchronously or asynchronously, results in a test failure. This can be controlled using the Expectation API.
* The class will extend `Cspray\Labrador\AsyncUnit\TestCase` and cannot have a constructor. If something is required that would otherwise be done in a constructor check out the next section for [TestCase Hooks](/async-unit/tutorials/testcase-hooks.md).
