Skip to content


Drush's test suite (aka Unish) is based on PHPUnit. In order to maintain high quality, our tests are run on every push. See CircleCi.


  1. git clone
  2. cd drush
  3. composer install
  4. Review the configuration settings in tests/phpunit.xml.dist. If customization is needed, copy phpunit.xml.dist to phpunit.xml and edit away.
  5. Run all test suites: composer test



Drush's own tests may be run within provided Docker containers via DDEV

  • Start containers: ddev start
  • Run a test: ddev exec drupal composer functional -- --filter testUserRole
  • See the DDEV's XDebug docs for help on enabling Xdebug.

Advanced usage

  • Run only one test suite
    • composer unit
    • composer integration
    • composer functional
  • Run only tests matching a regex: composer functional -- --filter testUserRole
  • Skip slow tests (usually those with network usage): composer functional -- --exclude-group slow
  • XML results: composer functional -- --log-junit results.xml
  • Ad-hoc testing with the SUT

About the Test Suites

  • Unit tests operate on functions that take values and return results without creating side effects. No database connection is required to run these tests, and no Drupal site is set up.
  • Integration tests set up a test dependency injection container and operate by calling the Symfony Application APIs directly. A Drupal site called the System Under Test is set up and used for the tests. The SUT is set up and installed only once, and then is re-used for all tests. Integration tests therefore cannot make destructive changes to the SUT database. Also, Drupal is bootstrapped only once (always using the standard Drupal kernel, never the install or update kernel). This means that all commands run at @bootstrap full, and it is not possible to test loading different Drush configuration files and so on. It is not possible to test argument / option parsing. The shutdown and error handlers are not installed, so PHP deprecation warnings will be evidenced in the integration tests.
  • Functional tests operate by execing the Drush executable. All functional tests therefore run in their own separate processes. The Drupal System Under Test is set up every time it is needed by any functional test. It is therefore okay if a functional test changes the state of the SUT. The codebase is re-used, so no destructive changes should be made to the code.

Drush Test Traits

Drush provides test traits that may be used to test your own Drush extensions. Adding the traits varies slightly depending how you package your Drush extension.

Once you successfully have use Drush\TestTraits\DrushTestTrait in your test class, you are able to write simple tests that call your extension's commands and makes assertions against the output.

    public function testMyCommand()
        $this->drush('my:command', ['param'], ['flag' => 'value']);
        $this->assertOutputEquals('The parameter is "param" and the "flag" option is "value"');

Last update: June 7, 2023
Authors: Moshe Weitzman