Search code examples
phplaravelunit-testingeloquentintegration-testing

Can I change this feature test to a unit test?


I have written two tests: one that makes a post request to an endpoint and awaits for a specific response containing status and message; and another one making the exact same request, but instead of await a response, it verifies if the database has the data matching what I just sent. Both these test are feature tests, and so far I have no unit test in my application; that happens because I have tested endpoint only.

So my idea is the following: instead of making a call to an endpoint in my second test, I could directly test my service method that creates a new register to the database. Would this be a valid unit test?

Personally, I think it would be valid because I am isolating a specific method and testing if the code works, and not if the integration works, even though there's integration of my code with the DB (Eloquent), my service method is the closest testable thing to the DB I have in my system.

My two tests, in the order I specified above:

/** @test */
  public function a_group_can_be_created()
  {
    $this->withoutExceptionHandling()->signIn();

    $group_data = [
      'name' => $this->faker->word(),
      'status' => $this->faker->boolean(),
    ];
    $modules = ['modules' => Modules::factory(1)->create()->pluck('id')];

    $response = $this->post(route('cms.groups.store'), array_merge($group_data, $modules));

    $response->assertSessionHas('response', cms_response(trans('cms.groups.success_create')));
  }

  /** @test */
  public function creating_a_group_persists_its_data_to_the_database()
  {
    $this->withoutExceptionHandling()->signIn();

    $group_data = [
      'name' => $this->faker->word(),
      'status' => $this->faker->boolean(),
    ];
    $modules = ['modules' => Modules::factory(1)->create()->pluck('id')];

    $this->post(route('cms.groups.store'), array_merge($group_data, $modules));

    $this->assertDatabaseHas('groups', $group_data);
    $this->assertDatabaseCount('modules', 2);
    $this->assertDatabaseCount('group_modules', 2);
  }

Solution

  • Unit test in laravel "do not boot your Laravel application and therefore are unable to access your application's database or other framework services"

    With that said, you can't access any database with a facade or with your eloquent model

    so if you change your feature testing to unit testing, it will fail.

    Unit test will work well if you don't use any of laravel framework utilities. I occasionally use it for testing a little self made library

    But if you want to isolate it and create feature testing without calling the API endpoint, it will works too. It's really up to you to decide whether it is necessary to do that or not. But keep in mind that unnecessary test will make the test longer, especially if you use RefreshDatabase or DatabaseMigration trait. It will quite annoying to wait for them to finish