Getting Started

TestCases are the fundamental building block in AsyncUnit. Write tests and use hooks to setup and tear down necessary state.

Installation

Composer 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.

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. The TestCase provides methods that access the Assertion API. A minimally working example, that compares 2 strings, would look something like the following...

<?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:

vendor/bin/asyncunit run tests

You could expect to see output like the following:

Test output when you're all green!

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
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
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.