Structure a new test by writing comments first

Test cases are usually split into two or three sections - "Arrange, Act, Assert" or "Given, When, Then".

If the test has a prerequisite, such as some users or content to be created or in a given state, you create the required environment for the test. With unit tests, this would include mocking any dependencies you need to use.

Then you perform an action on the subject under test and, finally, assert that the system is in the desired state.

Maybe a user was pending initially, and they're active after running a command or a cron task. You can assert the initial state of the user as well as the final state to ensure the action did what it was supposed to do.

Option 1

To help me get started, I'll sometimes write a test like this with placeholders to separate the test into its separate stages:

/** @test */
function should_activate_a_pending_user(): void {
// Arrange.

// Act.

// Assert.
}

This makes me think about the different stages and what each might need to contain.

Option 2

Or I might write it out in the "Given, When, Then" format:

/** @test */
function should_activate_a_pending_user(): void {
// Given I have a user.
// And the user is pending.

// When I run the user update command.

// Then the user should no longer be 'pending'.
// And the user status should be 'active'.
}

This takes a little longer to write but feels more familiar if you're used to a behavioural testing framework like Behat.

Either way, sometimes, I'll remove the comments once I've written the code around them or leave them to provide additional context.