---
title: 'ATDC: Lesson 1 - Zero to Test'
permalink: /atdc/1-zero-to-test
---
{% block head_meta %}
{% endblock %}
{% block content %}
In this lesson, we start from scratch and end with a working test suite.
## Creating a Drupal project
If you don't have one, you'll need a new Drupal project to work on. I'd suggest using Drupal 10.2 and the instructions at .
You'll need [PHP](https://www.php.net/manual/en/install.php) and [Composer](https://getcomposer.org/doc/00-intro.md).
First, run `composer create-project drupal/recommended-project drupal` followed by `cd drupal && composer require --dev drupal/core-dev` to add the development dependencies, including PHPUnit.
At this point, you should have a `web` directory and a `phpunit` file within `vendor/bin`.
Finally, run `php -S 0.0.0.0:8000 -t web` to start a local web server.
You don't need to install Drupal - as long as you see the installation page, that's fine.
## Creating a custom module
Before adding tests, you must create a module to place them in.
Run `mkdir -p web/modules/custom/atdc` to create an empty module directory and create an `atdc.info.yml` file within it with this content:
```yaml
name: ATDC
type: module
core_version_requirement: ^10
package: Custom
```
This is the minimum content needed for a module to be installable.
### Writing your first test class
Test classes are located in each module's `tests/src` directory.
Run `mkdir -p web/modules/custom/atdc/tests/src/Functional && touch web/modules/custom/atdc/tests/src/Functional/ExampleTest.php` to create the directory structure and a blank test class.
Then, add this content.
```php
PHPUnit\TextUI\RuntimeException: Class "Drupal\Tests\BrowserTestBase" not found.
This isn't an assertion failure, but PHPUnit needs help finding the files it needs to run.
To fix this, let's configure PHPUnit.
## Configuring PHPUnit
Create a new `phpunit.xml.dist` file at the root of your project with this content:
```xml
./web/modules/**
```
This is based on `web/core/phpunit.xml.dist` with project-specific changes.
Namely, setting the `bootstrap` value to include the `web/core` path, fixing the error, and populating the `SIMPLETEST_BASE_URL` and `SIMPLETEST_DB` environment variables.
PHPUnit now knows where the files are, to connect to Drupal at (matching the PHP web server address) and an SQLite database.
I've also added a `testsuite` that declares where any test classes will be located so the path doesn't need to be specified on the command line.
## Re-running the tests
Re-running the tests will give the expected error about a failing assertion:
> Failed asserting that false is true.
Fix the assertion in the test by changing `FALSE` to `TRUE`, run `vendor/bin/phpunit` again, and you should see a passing test.
> OK (1 test, 2 assertions)
## Improving the tests
Now you have as passing test and know PHPUnit is working, let's improve it.
Instead of the basic check, let's check whether certain pages exist and are accessible.
To keep things simple and focused on writing and running tests, let's use some standard Drupal pages - the front and administration pages instead of writing your own.
As you're writing functional tests by extending `BrowserTestBase`, you can make HTTP requests to the web server and make assertions on the responses.
Replace the `testBasic` test method with the following:
```php
public function testFrontPage(): void {
$this->drupalGet('/');
$this->assertSession()->statusCodeEquals(Response::HTTP_FORBIDDEN);
}
public function testAdminPage(): void {
$this->drupalGet('/admin');
$this->assertSession()->statusCodeEquals(Response::HTTP_OK);
}
```
These tests will make HTTP requests to the specified paths and assert the status code on the response matches the expected values.
I'm using the constants on the `Response` class, but you can also use the status code numbers - e.g. `200` and `403`.
## Running the updated tests
Running `vendor/bin/phpunit`, you'll get two errors:
> 1) Drupal\Tests\atdc\Functional\ExampleTest::testFrontPage
> Behat\Mink\Exception\ExpectationException: Current response status code is 200, but 403 expected.
>
> 2) Drupal\Tests\atdc\Functional\ExampleTest::testAdminPage
> Behat\Mink\Exception\ExpectationException: Current response status code is 403, but 200 expected.
>
> ERRORS!
> Tests: 2, Assertions: 4, Errors: 2.
The responses are not returning the expected status codes, so the tests are failing.
Reviewing them, the front page should return a 200 response code (`HTTP_OK`) as it's accessible to all users, including anonymous users.
As you're logged out, the administration page should return a 403 (`HTTP_FORBIDDEN`).
Swapping the assertions should get the tests to pass.
Now, running `vendor/bin/phpunit` returns no errors or failures.
> OK (2 tests, 4 assertions)
Congratulations!
## Conclusion
In this lesson, you've created a new Drupal 10 project, configured PHPUnit and created a custom module with your first passing browser tests.
From this, you can hopefully see that automated testing doesn't need to be difficult, and the configuration you've done here will work for the upcoming lessons, where you'll expand on what you've done and explore more that Drupal and PHPUnit have to offer.
[atdc]: https://www.oliverdavies.uk/atdc
{% endblock %}