Using the Test Harness

When creating an application with aqueduct create, a test harness class is available in test/harness/app.dart. It is responsible for starting a temporary, local instance of an application before tests run and stopping it once tests have finished.

It is required that you run the aqueduct setup command prior to running Aqueduct application tests. (See Getting Started.)

A test file, then, only needs to import this harness and start and stop the application to enable testing. Here's an example of a test file:

import 'harness/app.dart';

void main() {
  TestApplication app = new TestApplication();

  setUp(() async {
    await app.start();  

  tearDown(() async {
    await app.stop();

  test("...", () async {
    var response = await app.client.request("/endpoint").get();
    expect(response, hasStatus(200));

Note that the app harness file exports the Dart test package and Aqueduct's test helper package.

Before each test is run, the TestApplication harness is started. This harness starts your application running locally. Tests can issue requests to the application through its client, which is covered in more detail here.

There are a few important details to understand about the TestApplication when it is started.

An Aqueduct application will likely read values from a configuration file. The convention for configuration files in Aqueduct applications is to have two files: a template file that is checked into version control (config.yaml.src) and a deployed file that exists on a machine running a deployed instance of the application (config.yaml).

By default, a project created with aqueduct create follows this convention. The file config.yaml.src is created when the project is created. It is the 'template' for your application's configuration file. As your configuration needs change, your modify the config.yaml.src file to include all of the keys that a deployed config.yaml file should have.

The test harness uses the values from config.yaml.src to configure the test instance of the application. This is very valuable: it ensures that the application you are testing is being configured in the same way as the deployed application. It also allows you to choose appropriate test configuration values for your test application so that things that need to be mocked can be driven by the values in the template configuration file.

On startup, the TestApplication will add a temporary version of your application's database schema to a local database. The database connection information comes from config.yaml.src - which defaults to and should stay postgres://dart:[email protected]:5432/dart_test. This database is set up by the aqueduct setup command. Once your tests run, all of the created tables are deleted.

Because most applications will use Aqueduct's Auth framework, it is required that an application have valid client ID and client secrets during testing to issue authorization tokens. By default, a single client ID/secret pair is added when starting the application: com.aqueduct.test/kilimanjaro. If your application uses scopes or has behavioral differences for client IDs, you'll need to add those client IDs with TestApplication.addClientRecord. This can be done by adding the code to the test harness's start method.

You may modify the TestApplication to do any additional work that your application needs to do prior during startup.

A TestApplication has a client property that executes requests against the application. The client is configured such that making requests only requires the path. The following sends a request for GET /users to the application, regardless of the host or port the application is listening on.

var app = new TestApplication();
var response = await app.client.request("/users").get;

More details about the client are available in the next guide, TestClient.

Lastly, a TestApplication runs its RequestSink on the main isolate - the same isolate that is running your tests. This allows your tests to peek at values inside the RequestSink and ensures there is only one database connection, since that connection is the only one that has access to the database schema.