Hooks

Pest hooks are similar to the steps that you might take when preparing a meal - first, you gather and prepare the ingredients, then you cook the meal, and finally, you clean up after yourself. In the same way, hooks allow you to perform specific actions before and after each test or file, such as setting up test data, initializing the test environment, or cleaning up resources after the tests are complete.

By using hooks in Pest, you can streamline your testing process, automate repetitive tasks. Whether you're writing unit tests for a small project or building a complex test suite for a large application, hooks can help you save time and improve the quality of your tests.

In addition, if you wish to run a hook only for a specific group of tests, you may include the hook within a describe() function.

1beforeEach(function () {
2 //
3});
4 
5describe('something', function () {
6 beforeEach(function () {
7 //
8 });
9 
10 //
11 
12 describe('something else', function () {
13 beforeEach(function () {
14 //
15 });
16 
17 //
18 });
19});
20 
21test('something', function () {
22 //
23});

Here's a list of the hooks that are available in Pest:

beforeEach()

Executes the provided closure before every test within the current file, ensuring that any necessary setup or configuration is completed before each test.

1beforeEach(function () {
2 // Prepare something before each test run...
3});

When using the beforeEach() hook, it's possible to initialize properties that will be shared across all tests within the current file. For example, you could use beforeEach() to initialize the $repository property before each test is run, ensuring that it's available for subsequent tests in the file.

1beforeEach(function () {
2 $this->userRepository = new UserRepository();
3});
4 
5it('may be created', function () {
6 $user = $this->userRepository->create();
7 
8 expect($user)->toBeInstanceOf(User::class);
9});

afterEach()

Executes the provided closure after every test within the current file, allowing you to clean up any resources or state that may have been modified during testing.

1afterEach(function () {
2 // Clear testing data after each test run...
3});

So, using the example above, if the beforeEach() hook is used to initialize the $userRepository property, the afterEach() hook may be used to "clean" it after each test if necessary. This ensures that any resources the object may be using are released or reset between tests, preventing any interference or unwanted behavior.

1afterEach(function () {
2 $this->userRepository->reset();
3});

Optionally, you can use the after() method to perform clean-up tasks after a specific test. This is useful when you need to clean up resources that are specific to a single test, rather than shared across all tests in the file.

1it('may be created', function () {
2 $this->userRepository->create();
3 
4 expect($user)->toBeInstanceOf(User::class);
5})->after(function () {
6 $this->userRepository->reset();
7});

beforeAll()

Executes the provided closure once before any tests are run within the current file, allowing you to perform any necessary setup or initialization that applies to all tests.

1beforeAll(function () {
2 // Prepare something once before any of this file's tests run...
3});

It's important to note that unlike the beforeEach() hook, the $this variable is not available in the beforeAll() hook. This is because the hook runs before any tests are executed, so there is no instance of the test class or object to which the variable could refer.

afterAll()

Executes the provided closure once after all tests have completed within the current file, allowing you to perform any necessary clean-up or tear-down tasks.

1afterAll(function () {
2 // Clean testing data after all tests run...
3});

Just like the beforeAll() method, the $this variable is not available in the afterAll() hook. This is because the afterAll() hook typically runs after all tests in the file have completed, so there is no longer a test instance or object to which the variable could refer.


Once you've mastered using hooks to set up preconditions and clean-up actions for your tests, we're ready to discuss "Datasets", which allow you to run the same test with different inputs or parameters. Datasets can be used to thoroughly test your code under a variety of conditions and edge cases, letting you identify and fix bugs that may not be immediately obvious: Datasets →