pest: Using factories in beforeAll/afterAll hook throws InvalidArgumentException

Hey,

Reproducible with clean project:

laravel new pest-beforeAll
composer require pestphp/pest --dev --with-all-dependencies
composer require pestphp/pest-plugin-laravel --dev
php artisan pest:install

Refactor the default ExampleTest.php to Pest and try to create User factory in beforeAll/afterAll hook:

<?php

use App\Models\User;
use function Pest\Laravel\be;
use function Pest\Laravel\get;

beforeAll(function(){
  be(User::factory()->create());
});

test('basic test', function(){
  get('/')->assertStatus(200);
});

Run php artisan test and it will fail with:

Screenshot 2020-12-29 at 15 49 37

When using beforeEach instead of beforeAll the tests pass. ✨

Sorry that this didn’t come with a pull request - haven’t tinkered with reflection that deep and I bet given that it’s reproducible someone from the core contributors will have easier time fixing this. Alternatively if someone could provide some pointers as to what might be the cause I can take a look and try to figure it out. 🤓

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 2
  • Comments: 18 (7 by maintainers)

Most upvoted comments

A very strange solution, making the use of Pest very questionable. How do I set up group of tests?

@ilyavaiser I agree with you, as I am having the same issue. I need to test a table sorting, and for each test case, I need to seed my DB again and again with the same data, which influences the performance of the test. In fact, it should be done only once.

@nunomaduro it doesn’t mention there the fact that the framework hasn’t booted and you can only run basic code. Would be a nice touch for new adopters who don’t know/haven’t used PHPUnit and jump right in to PestPHP. 🚀

I second the request. I’m starting using Pest too since yesterday and it take me a while to understand that the class isn’t instantiated during beforeAll() which i find it odd, so i thought i was doing something wrong.

So i think that beforeAl() should be instantiated after the class is initialized, it should be a good gain on performance time if we have to load the fixtures once for the class instead of each test.

Edit: im using Symfony and not Laravel

This is a known “issue”, beforeAll / afterAll are called before (or after) the class has been instantiated (they are the equivalents of @beforeClass and @afterClass in PHPUnit). So the framework hasn’t been booted at that point. 👍🏻 In the meantime you need to use beforeEach/afterEach. See https://github.com/pestphp/pest/issues/237 and https://github.com/pestphp/pest/issues/33#issuecomment-658022624. 🙂 I think that Nuno was thinking about a possible way of resolving this though. 🤔

It’s not really an issue, just a lot of people seem to get confused with beforeAll() / beforeEach() not working like how setUp() and tearDown() work.

@nunomaduro it’s obvious from the previous comments and likes that a lot of devs want to be able to access framework functionalities, e.g factories, artisan commands, etc once before the whole test runs and hence access to the application’s booted state. Is there a way out to do this without having to repeat executions in the beforeEach hook?

I must admit that even I didn’t know about the @beforeClass restrictions because I hadn’t used them in Laravel. 😄

That note seems Laravel specific.