testing php applications

Test Organisation And Naming

A test suite is production code for developers. Clear file structure and names make failures faster to diagnose and make missing scenarios easier to notice during review.

Name The Behaviour

A useful test name describes the situation and expected outcome: testCheckoutRejectsExpiredDiscountCode() communicates more than testDiscountCode(). Keep one main reason to fail in each test.

Organise By The Codebase

Mirror the repository where that helps navigation: unit tests for domain rules, integration tests for repositories or adapters, and feature or HTTP tests for application workflows. Keep shared test helpers small; a deep inheritance tree can hide important setup.

PHP example
<?php

declare(strict_types=1);

use PHPUnit\Framework\TestCase;

final class CheckoutTest extends TestCase
{
    public function testCheckoutRejectsExpiredDiscountCode(): void
    {
        // Arrange the expired code, submit checkout, and assert the rejection.
    }
}

The method name makes the failed behaviour visible in CI output. The body should arrange only the state needed for that scenario.

Common Mistakes

  • Names such as testItWorks() that reveal nothing when CI fails.
  • One giant test that checks several unrelated rules.
  • Copy-pasted setup that obscures the meaningful state.
  • Helpers so abstract that readers cannot see the scenario.

What To Practise

  • Name tests after behaviour.
  • Group tests at useful boundaries.
  • Keep setup readable and local when possible.

Practice

Practice: Rename A Weak Test List

Improve a set of vague test names for a product publishing feature.

Requirements

  • Cover successful publishing.
  • Cover a missing title.
  • Cover an ordinary user attempting an admin action.
  • Keep each name focused on one outcome.
Show solution

The names should explain CI failures before the file is opened.

PHP example
<?php

declare(strict_types=1);

$testNames = [
    'testAdminCanPublishValidProduct',
    'testPublishingRejectsProductWithoutTitle',
    'testOrdinaryUserCannotPublishProduct',
];

foreach ($testNames as $name) {
    echo $name . PHP_EOL;
}

// Prints:
// testAdminCanPublishValidProduct
// testPublishingRejectsProductWithoutTitle
// testOrdinaryUserCannotPublishProduct

Each test name identifies the actor or input condition and one expected result.