[policy, no patch] Discuss the standards for phpunit based tests

Created on 5 August 2013, almost 12 years ago
Updated 6 June 2025, 1 day ago

Updated: Comment #11

Problem/Motivation

Discussion and guidance are needed on the issue of coding standards for PHPUnit-based tests.

Proposed resolution

Write up some standards, have a review period, and make a handbook page.

Remaining tasks

Reconcile these against the SimpleTest coding standards: https://drupal.org/node/325974

Discuss pros and cons of various standards.

Add the documentation tag.

Proposed PHPUnit Coding Standards (thus far)

Drupal core PHPUnit-based tests must:

Organization:

  • Exist inside the /core/tests directory.
  • Have a classname that is the name of the class under test, plus 'Test.' For instance: The class SuperCoreInjectable would be tested by SuperCoreInjectableTest.
  • Live in the same namespace as the class under test, plus \Tests. Thus: Drupal\Core\SuperStuff\Tests\SuperCoreInjectableTest
  • Each test class must reside in its own file, discoverable under the standard PSR-0/PSR-4 system for Drupal: /core/tests/Drupal/Core/SuperStuff/Tests/SuperCoreInjectableTest.php

Documentation:

  • Use @group Drupal to allow filtered testing.
  • Use @group Namespace or similar for further filtering. e.g: @group Entity
  • Use @coversDefaultClass and @covers where appropriate to prevent false positive test coverage reports. @covers documentation
  • Only use @covers to reflect methods called from within the test method. That is, if you assert the result of \Foo::bar() you can't claim coverage of \Foo::privateMethodThatBarCalls(). @covers for methods should not use trailing parentheses. So @covers ::foo and not @covers ::dontDoThis()
  • Use @see to link to the class which is tested.

Best Practices:

  • Tests must pass under --strict. This means, for instance, that all tests must make an assertion.
  • Isolate tests as much as possible, using a rule of thumb that each method being tested should have its own test method. Test methods were expensive in SimpleTest; in PHPUnit they're cheap.
  • Use annotation features of PHPUnit as much as possible. These include @dataProvider, @expectedException, and so forth.
  • Always use a @dataProvider method if there is any data for testing. This allows us to separate concerns, so that we don't have to refactor tests to accommodate data, only change the data.
  • Where possible, name data provider methods the same as their test method counterpart, removing the Test and prepending with provider. For example: testSuperCoreCanInject() would have a data provider of providerSuperCoreCanInject(). This is a guideline, and it may make more sense to have a readable method name rather than one that starts with provider*. Strive to be consistent within the test class, at least, so that it's easy to pick the provider methods from a list of methods.
  • Use @expectedException where possible.
  • Mock as much as possible (using PHPUnit's getMock()).
  • Use sentence-style test method names, such as testFrammistatWithGoodData() and testFrammistatForException(), to make code readable, and to help various reporting systems provide useful output. (See ./vendor/bin/phpunit --testdox for details.)
  • When possible, use reflection to gain access to private and protected methods for testing. This allows you to perform the test without creating a stub subclass.
  • When using reflection to gain access to private and protected methods is unfeasible or impractical, test-scope-only subclasses of classes under test should be named Stub plus the name of the class. Example: StubSuperCoreInjectable extends SuperCoreInjectable {}. These subclasses can be declared in the same file as the test class which uses them, since they should be small, minimal implementations.
📌 Task
Status

Needs review

Component

Coding Standards

Created by

🇩🇪Germany dawehner

Live updates comments and jobs are added and updated live.
  • Coding standards

    It involves compliance with, or the content of coding standards. Requires broad community agreement.

  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇬🇧United Kingdom joachim

    PHPUnit annotations are now attributes -- IS needs an update for this.

    > Use @group Drupal to allow filtered testing.
    > Use @group Namespace or similar for further filtering. e.g: @group Entity

    What is the point of this? If all the Drupal core tests are in core/tests, then you pass that as a parameter to PHPUnit instead of a @group.
    If all the tests for core/lib/Core/Foo are in core/tests/Foo, then you pass that.

    Given how much people are complaining about writing docblocks for test methods in 📌 [policy] Remove the requirement for doxygen for test methods Needs work , why are we adding superfluous @group tags?

Production build 0.71.5 2024