Generally, if you're asserting that the DB has a record then it's a feature test.
Is my feature test actually a unit test?
Hello, people. 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);
}
@BernardoBF4, yes, depending on what that service does.
This is perhaps more clear in Pest, which would typically have the line:
uses(TestCase::class)->in('Feature');
to signify that all tests in the tests/Feature directory should extend Test\TestCase whereas all tests in tests/Unit would by default extend PHPUnit\Framework\TestCase.
I look at it this way: if a test needs to extend Test\TestCase in order to pass then it's a Feature test. Test\TestCase is generally responsible for creating the application ($this->app), setting up the test databases and using database transactions (RefreshDatabase), and faking queues, disks, etc.
A unit test's only dependency should be itself. For example,I have a global helper method named iszip() that validates zip codes, the unit test for that method only depends on itself and looks like:
it('validates zip codes', function ($zip, $bool) {
expect(iszip($zip))->toBe($bool);
})->with([
['78456', true],
['78944-4565', true],
[87456, true],
['784554', false],
['78455-45612', false],
['not zip code', false],
]);
Of course, you are free to move a 'Feature' test to the' Unit' directory and organize things however you want, but there's nothing wrong with only having feature tests for a service if that's what they really are. Don't try to fit a round peg into a square hole just to have 'unit tests'.
Please or to participate in this conversation.