Using Laravel Model Factories in PHPUnit Data Providers
Published on 2024-02-03
If you’ve ever tried to use a Laravel model factory inside a PHPUnit data provider, then you were likely greeted with an error message resembling "A facade root has not been set"
. After scratching your head for a few minutes, you probably (wisely) decided that life is too short and then promptly scrapped the whole approach. The issue that you encountered is an expected consequence of the lifecycle of PHPUnit tests. In PHPUnit, data providers are called before a test’s setUp
method. If you look inside the Illuminate\Foundation\Testing\TestCase
class, which is the abstract class that Laravel feature tests ultimately extend, you’ll see the following snippet:
The setUp
method inside that class is responsible for booting the Laravel framework in tests via the refreshApplication
method. As data providers are executing before that setUp
method has been called, you’re not going to have access to Laravel functionality such as facades and model factories at that point. You might think that this is the end of the road for using model factories inside your data providers. Fear not, there’s a neat trick that you can use to get around this limitation. If you wrap the provider’s data set within a closure, this will cause the expression to be evaluated lazily.
The above approach does have the downside of requiring you to invoke the Closure
inside the body of your test, but it’s a relatively small price to pay. For the sake of completeness, I’ve included examples of returning a singular User
model in a data set as well as returning an array of User
models.
If you want to learn more about PHPUnit data providers outside of the previously linked documentation, then I would highly recommend this blog post by Matt Barlow.