Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jj15's avatar
Level 10

When Should a Unit Test Become a Feature Test?

I'm really sorry to have to add to the pile of questions like this but I just need to affirm whether or not my strategy and understanding is a proper one. šŸ˜„

I'm currently learning about testing through Laravel Daily's beginner testing course and got a bit hung up with Unit vs. Feature tests. I believe I get the basic differences between each (Unit is for testing the small, 'internal' pieces of our code, such as service classes, independently and in isolation (mocking dependencies) and Feature is for testing the "bigger picture" of our application, usually by testing our routes and controller actions like a user would).

From reading the Laravel docs I see that "Tests within your "Unit" test directory do not boot your Laravel application and therefore are unable to access your application's database or other framework services."

Let's say that I have a service class in which a method or two calls on the Storage facade, I would be unable to access or mock it in a unit test (as it doesn't extend Laravel's own TestCase class and boot the framework) should it then be "upgraded" to a feature test? Or is it advisable to still keep it a unit but extend it from Laravel's own TestCase class? (It seems that Unit tests used to do this but changed around 3 or so years ago).

I may be overthinking things too much, but I just haven't been able to come to a good conclusion, and Googling and looking at other answers here doesn't seem to answer my specific questions.

Thanks.

0 likes
3 replies
LaryAI's avatar
Level 58

In general, a unit test should remain a unit test and a feature test should remain a feature test. However, there may be cases where a unit test needs to access certain Laravel services or functionality that is not available in a pure unit test. In these cases, it may be appropriate to upgrade the test to a feature test.

One approach to consider is to use Laravel's TestCase class as the base class for all tests, including unit tests. This will allow you to access Laravel services and functionality in your unit tests, while still keeping them focused on testing individual units of code.

Another approach is to use dependency injection to provide mock or stub implementations of the services or functionality that your unit test needs. This can help keep your unit tests isolated and focused on testing individual units of code, while still allowing you to test the interactions between those units and the rest of your application.

Ultimately, the decision of when to use a unit test vs. a feature test will depend on the specific requirements of your application and the goals of your testing strategy. It's important to keep in mind the differences between the two types of tests and to choose the appropriate approach for each situation.

Example code for using Laravel's TestCase class as the base class for a unit test:

use Tests\TestCase;

class MyUnitTest extends TestCase
{
    public function testSomething()
    {
        // Use Laravel services or functionality here
    }
}
lukedowning19's avatar
Level 24

Hey there! You're correct: unit tests do not have access to the Laravel framework. This means that tests that hit controllers, jobs, or any class that has a reliance on the Laravel framework being booted are essentially feature tests.

What constitutes a unit test at this point can be a bit muddy, as in your example; you have a class that is a plain service but happens to rely on a couple of Laravel facades. You have a couple of options:

  1. Use dependency injection in the class constructor instead of the facades, and pass those dependencies down to the class in your test. You could even create your own contracts and implementations, but that is usually overkill.
  2. Change the extended TestCase instance, as you mentioned. However, this can cause confusion as you are mixing and matching, and basically removing the primary distinction between the two directories.
  3. Create a third testing directory: "Acceptance", where you do end-to-end controller tests and similar, and use "Feature" for testing classes that rely on the framework but don't go through routing or the queue.

It tends to be more work to write unit tests, because it means you can't make free use of the Laravel framework, but the end-result tends to be abstracted code that isn't as dependant on the framework, and faster tests. Whether or not that appeals to you and is worth the tradeoff is your decision, and I won't try to sway you one way or the other.

1 like
jj15's avatar
Level 10

@LukeDowning19

Thank you for responding, Luke!

This makes me feel much better and a bit more confident now, I was just afraid to do things that way, and a few years down the line somebody tells me "You're doing this all wrong!" (but of course everyone will always have their own opinion).

1 like

Please or to participate in this conversation.