Ground Level PHP Testing
========================

A PHPUnit testing library designed to expedite creation and management of PHPUnit
integration tests for WordPress plugins and projects.

---

This package is intended to be defined as a composer requirement for any WordPress plugin projects which require
PHPUnit tests.

The package includes utilities to facilitate setting up tests with an opinionated structure. It also allows most dependencies
to be defined in this project so that other projects don't have to independently manage test dependencies.


## Requirements

The scripts in this package require PHP 7.4 or later and MySQL 8.0-8.3 (MariaDB 10.6-11.3)

Additional dependencies that must be installed and available on your system include:

+ Subversion - `svn`
+ cURL - `curl`

## Supported Environments

### Windows

The library has been confirmed to work in Windows:

+ [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) (on Ubuntu 20.04.6 LTS) 
+ [Cygwin](https://www.cygwin.com/).

## Linux

The library should work on any Linux distribtion after the above requirements are met.

## macOS

The library should work on macOS after the above requirements are met.

Recent versions have later versions of PHP and MySQL installed by default and you may need to downgrade the default versions to match the library's requirements.

## Installation

Initialize a composer project if you haven't already, either in the project dir or on the `tests/` dir:

```bash
composer init
```

And then require this package as a dependency:

```bash
composer config repositories.caseproof composer https://pkgs.cspf.co
composer require --dev caseproof/ground-level-php-tests
```

Following installation you'll probably want to add shortcut scripts to the `scripts` object in `composer.json`.

```json
{
  "scripts": {
    "install:wp": "@tests-php install-wp",
    "tests-php": "./vendor/bin/cspf-tests-php",
    "test": "./vendor/bin/phpunit"
  }
}
```

You'll also want to ensure that after installation you'll have access to the `cspf-tests-php` script. Run `composer run tests-php -- --help` to see
all the available commands.


## Bootstrapping the Project with the `scaffold` command

To setup the project with all the necessary files to execute PHPUnit tests run the `scaffold` command:

```bash
composer run tests-php scaffold -- --package-name "ExampleNamespace"
```

Because parameters are passed from composer to the installer, slashes require additional escaping. For example, to pass `Your\Namespace` as the package name:

```bash
composer run tests-php scaffold -- --package-name "Your\\\Namespace"
```

This command will create the following files in the directory where the `composer.json` is located:

### phpunit.xml.dist

The PHPUnit configuration file. This file shouldn't require any modifications, at least at first.

This command will create the following files in your `tests/` directory:

### bootstrap.php

The primary PHPUnit test bootstrap file. You shouldn't make any changes to this file. As it may be overwritten in the future
if global changes are made to this project.

### bootstrap-extra.php

An additional bootstrap file that's included by `bootstrap.php`.

If your project requires any custom bootstrapping during testing you can add those steps into this file. It's also safe to
delete this file if you don't need it.

### Framework/TestCase.php

The base unit test case file that all the project's test cases should extend. Any additional custom test utilities can
be added to this file.

### Framework/WPTestCase.php

The base unit test case file that all the project's test cases that explicitly rely on WordPress should extend. Any additional custom test utilities can be added to this file.

If you need to add any additional testing framework files, you should do so in this directory.

In order to ensure these files are autoloaded, you should add the following to your `composer.json` file, replacing "ExampleNamespace"
with the `--package-name` passed when you ran the `scaffold` command.

```json
{
  "autoload-dev": {
    "psr-4": {
      "ExampleNamespace\\Tests\\": "./path/to/tests/"
    }
  },
}
```

### TestCases/SampleTest.php

A sample test case file as an example that can be modified or deleted.

All test cases should be created in this directory and should mimic the directory structure of the application. For example
an application file located at `app/Utilities/User.php` should have it's test file in `tests/TestCases/Utilities/TestUser.php`


## Installing Test Dependencies

The `cspf-tests-php` script provides an installation helper to facilitate downloading WordPress and WordPress testsing library
code as well as configure a testing database for use when running the test suite.

This script is a thin wrapper around the WP core `install-wp-tests.sh`. It provides default values and replaces the positional arguments
with named arguments.

```bash
OPTIONS
  -H, --help            Show this help message.
  -n, --name            The database name. Default: "$projectSlug_tests"
  -u, --user            The database username. Default: "root"
  -p, --pass            The database users password. Default: "password"
  -h, --host            The database host name and, optionally port. Default: "localhost:3306"
  -v, --version         The WordPress core version to download. Default: "latest"
  -t, --tmpdir          The relative path to the temporary directory where dependencies are stored. Default: "./tmp"
      --fresh           If provided, clears the --tmpdir and redownloads all dependencies.
      --skip-db-create  If provided, skips database creation.
```

If all the defaults work on your local machine, install the tests:

```bash
composer run install:wp
```

The most likely changes you may need to make are to the database username and password options. If you need to pass an empty
password, pass an empty string:

```bash
composer run install:wp -- --user myuser --pass ""
```

## Running Tests

Once configured, even with just the sample testcase created during scaffolding, you should be able to run tests:

```bash
composer run test
```


## Writing Tests

Once configured, you can begin writing tests. All tests should be created in the `tests/TestCases` directory. The directory
structure should mimic the structure of the application. For example, a class located at `app/Utilities/User.php` should have
it's test file located at `tests/TestCases/Utilities/UserTest.php`. All test case files must end in `Test.php`.

### Base Test Cases

Two base test case classes are included in this package: [TestCase.php](src/TestCase.php) and [WPTestCase.php](src/WPTestCase.php).

#### [TestCase.php](src/TestCase.php)

The `TestCase.php` class is a base test case class that provides a few helper methods for testing. It's intended to be used
for projects which don't explicitly rely on WordPress. It extends the base [PHPUnit TestCase](https://github.com/sebastianbergmann/phpunit/blob/main/src/Framework/TestCase.php) class.

#### [WPTestCase.php](src/WPTestCase.php)

The `WPTestCase.php` class is a base test case class that provides a few helper methods for testing. It's intended to be used
for projects which explicitly rely on WordPress. It extends the base [WP_UnitTestCase](https://github.com/WordPress/wordpress-develop/blob/trunk/tests/phpunit/includes/testcase.php) class.

### Snapshot Testing

Both base test case classes provide snapshot methods for snapshot testing provided by [spatie/phpunit-snapshot-assertions](https://github.com/spatie/phpunit-snapshot-assertions).

#### Test Case Traits

##### [FakesData.php](src/Traits/FakesData.php)

Provides access to the [Faker](https://fakerphp.github.io/) data generator.

##### [InvokesMethods.php](src/Traits/InvokesMethods.php)

Provides utilities for invoking protected and private methods on objects.

##### [ReadsProperties.php](src/Traits/ReadsProperties.php)

Provides utilities for reading protected and private properties on objects.

##### [WritesProperties.php](src/Traits/WritesProperties.php)

Provides utilities for writing protected and private properties on objects.

### Mock APIs

Mock APIs are included in this package to facilitate testing external APIs without loading the entire APIs library. These
APIs are not automatically loaded and must be explicitly loaded in your test suite's bootstrap file.

### Monkey Patching and Mocking with Brain Monkey

This package also includes the tests utility for PHP [Brain Monkey](https://github.com/Brain-WP/BrainMonkey)([documentation](https://giuseppe-mazzapica.gitbook.io/brain-monkey)).

#### [wp-hooks.php](src/mocks/wp-hooks.php)

This file provides a mock implementation of the WordPress hooks API. It's intended to be used in projects that do not
load the entire WordPress API during automated tests.

## Releasing Packages

To release the package:

1. Update the changelog: `composer run changelog` (or `composer run changelog -- --commit` to skip step 2).
    + By default the next version will be automatically selected based on semantic versioning.
      To specify a version, use `composer run changelog -- --ver=<version>` or specify
      a semantic version bump, eg `--major`, `--minor`, `--patch`, `--rc`, `--beta`, or `--alpha`.
2. Commit the changelog: `git commit -m "chore(release): <version>"`.
    + Automatically commit the changelog: `composer run changelog -- --commit`.
3. Push changes to remote: `git push origin main`.
4. Publish a release on GitHub: `gh release create`.
    4a. Use the most recent tag for the tag.
    4b. Use "Version <version>" for the title.
    4c. Use the changelog for the recent version as the release body.


## Testing the Package

The testing of this package is powered by [bashunit](https://bashunit.typeddevs.com/).

To install the testing dependencies, run `composer bashunit:update` from the root of the project.

The test suite can be run by executing `composer run test` from the root of the project.
