I’m trying to write a feature test in RESTful API that I have been created in laravel 8.
I have ChatController
that gets user chats by getUserChats
method:
// get chats for user public function getUserChats() { $chats = $this->chats->getUserChats(); return ChatShowResource::collection($chats); }
that called by this route:
Route::get('chats', [ AppHttpControllersChatsChatController::class, 'getUserChats' ]);
this is my feature test on this route:
public function test_get_user_chats() { // creates the fake user $user = User::factory()->create(); $this->actingAs($user, 'api'); // adds the chat to new fake user that created $response_create_chat = $this->json('POST', '/api/chats', [ 'recipient' => $user->username, 'body' => 'some chat text', ] ); $response_create_chat ->assertStatus(201) ->assertJsonPath('data.body', 'some chat text'); $response_get_chats = $this->json('get', '/api/chats'); $response_get_chats->assertStatus(200); }
the test runs successfully by this green output OK (1 test, 3 assertions)
but I don’t know this is the best way to implementing that.
so the question is that anything else I have to do in my test? am I doing the right feature test?
Advertisement
Answer
Generally, you want the scope of your test to be as small as possible. The test case that you provided is currently testing two separate api endpoints:
- Creating chats
- Getting chats
The issue with this is that if code related to creating chats breaks, your test case related to getting chats will fail.
I would recommend splitting these into two separate test cases. This will allow you to trust that if your test case for getting chats fails, it’s as a result of the code relating to getting chats failing rather than code unrelated to this endpoint.
I would also recommend using setUp
and tearDown
methods to ensure that your test case leaves the database in the same state that it found it. This ensures that other test cases will not have to concern themselves with the data from this test. This means the setUp
method should do things such as:
- Creating users
- Creating chats
The tearDown
method would be responsible for deleting the users and chats.
Additionally, you should test the format and data that is output by your endpoint. At the moment you are only checking for a 200 response code. If your api were updated to return a list of users rather than chats, the test case related to getting chats would still pass as it does not actually validate the data that is being returned.
EX:
class GetChatsTest extends TestCase { private User $user; public function testGetChats(): void { $chat = $this->json('get', '/api/chats'); // Check the chat's returned value $this->assertSame('Some parameters', $chat); } protected function setUp(): void { parent::setUp(); // Create the user in the setup. This is run before each test method is run. $this->user = User::factory()->create(); // Create the chat for the user (Pseudo code because I don't know how your code works) $this->user->createChat('Some parameters'); } protected function tearDown(): void { parent::tearDown(); // Delete the user and chats here, pseudocode again. This runs after every test method is run $this->user->deleteChats(); $this->user->delete(); } }
One thing to note about the example code is that it does not use the rest api to create the user or the chat but instead uses pseudocode controller methods to ensure that it isn’t dependent on the functionality of the chat api for testing.