sboulahr's avatar

Unit test the update method with laravel 8 and fakers

Alright so I'm pretty new to both unit testing, Fakers and laravel. I'm trying to unit test my resource controller, but I'm stuck at the update function.

Here's my controller:




public function update(Request $request, $id)
   {
       DB::beginTransaction();
       try {
      

           // update the status
           if ($bChangeStatus && $request->status === 'canceled') {
               Transport_order::where('order_id', $id)
                   ->whereNotIn('status', ['billed', 'delivered'])
                   ->update(['status' => 'canceled']);
           }
           // ....... the same if conditions for other status
           
      
           }
           DB::commit();
           return $oOrder;
       } catch (\Exception $e) {
           DB::rollback();
           abort(400, $e);
       }
   }

I have already made a test of the store method but I'm stuck with the update methode I can't handle it .

public function testStore_draft()
{
   Sanctum::actingAs($this->user, ['*']);
   $orderStore = array (
                 
       'external_ref' => '44' ,
       'contact_id'=> '19',
       'comment' => 'oioio',
       'user_id'=> '3',
       'doAssigned' => false,
       'doValidate' => false, 
     );
   $response = $this->json('POST', 'api/order',$orderStore,  $this->headers) 
   ->assertStatus(201)
        ->assertJsonFragment( ['status'=>'draft']); 

} 

Any help is welcome ! Thank you very much !

0 likes
6 replies
tykus's avatar
tykus
Best Answer
Level 104

For the update action, you need an existing Order instance to work with, and to do that, you need an OrderFactory:

// OrderFactory
public function definition
{
    return [
        'external_ref' => $this->faker->randomNumber(),
        'contact_id'=> Contact::factory(),
        'comment' => 'existing order',
        'user_id'=> User::factory(),
        'status' => 'draft',
    ];
}

Then, make the Order instance in the test using the factory, with some known state; which will be changed by the update action, for example:

function test_can_update_an_order()
{
	$order = Order::factory()->create(['status' => 'draft']); // other attributes from the factory definition

	$this->putJson("api/orders/{$order->id}", ['status' => 'cancelled'])
		->assertStatus(200)
		->assertJsonFragment(['status' => 'cancelled']);

	// Make assertions about other side-effects for **this** particular action.
}

Then make similar tests for other update scenarios.

1 like
sboulahr's avatar

Thank you very much . It was very helpful . But I still don't know why when I run my test I get

Expected status code 200 but received 404.
Failed asserting that 200 is identical to 404. 
Tray2's avatar

It does not find the route you are using in your test.

1 like
sboulahr's avatar

Thank you but I don't understand I defined the route in api.php

  Route::put('order/update', 'OrderController@update');
tykus's avatar

Two things are apparent (i) you have no Order id in the URI, so what would you be updating, and (ii) if you have defined this route in the api.php routes file, then the URI is prefixed automatically with api, i.e. api/order/update.

Typically we expect the update route to look like the following:

Route::put('order/{order}/update', 'OrderController@update');

This {order} wildcard becomes the $id parameter in the update action that you shared at the outset.

2 likes
sboulahr's avatar

Thank you very much It works perfectly

Please or to participate in this conversation.