jamesllewellyn's avatar

Unit Test for API POST not finding type hinted model Laravel 5.3

I'm new to unit testing and I'm having issues with testing an API endpoint that creates a new customer.

To be able to create a new customer I need to have an account and subaccount in which to add the new customer. So I first set them up using factories, and then I make a post to the API passing in the $account->id of the account I have just created, and the data needed to create a new customer.

The issue that I'm having is that in API method I have the account type hinted, however when I make the JSON POST request from this test file the account that I'm passing cannot be found.

I don't get a "No query results for model [App\Account]" exception as I would expect if that account didn't exist within the DB. Instead, I get an empty account object, so that when, within that method, I try to access data from the account I get "ErrorException: Trying to get property of non-object" exceptions.

I have tried not using the factories within the test file to create the account, and instead used an account that I know exists in the DB, and I still get the same error.

I have tried using postman to send that same JSON data that I have in the test file to the API endpoint, using the account Id of an account that I know exists, and this correctly creates the new customer.

I have tried removing the DatabaseTransactions trait and checking that the account that the factories are building is created correctly within the database, and it is, and then I've used postman to try and create a new customer within that account and it's been successful.

CreateCustomerTest.php


use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Customer;
use App\Company;
use App\Account;
use App\SubAccount;
use App\Address;
use App\Agent;
use Carbon\Carbon;


class CreateCustomerTest extends TestCase
{
    use WithoutMiddleware;
    use DatabaseTransactions;
    use DatabaseMigrations;


    /** @test */
    public function agent_can_create_new_customer()
    {
        $company = factory(Company::class)->create();
        $address = factory(Address::class)->create();
        $subaccount = factory(SubAccount::class)->create([
            'company_id' => $company->id,
            'address_id' => $address->id
        ]);
        $account = factory(Account::class)->create([
            'company_id' => $company->id,
            'site_id' => $subaccount->id
        ]);
        $agent = Agent::find(2);
        $this->actingAs($agent);
        //Arrange
        $response = $this->json('POST', "/api/account/{$account->id}/customer",[
            “foo”=>”bar”
        ],[ 'X-CSRF-TOKEN' => csrf_token()]);
        $this->assertResponseStatus(200);
        //Act
        $customer = Customer::where("foo", "bar”)->first();
        $address = Address::where('id',$customer->address_id)->first();
        //Assert
        $this->assertEquals( "bar", $customer->foo);
       
    }
}


api.php Route

    Route::post('/account/{account}/customer', ['uses'=>'CustomerApiController@addCustomer', 'as'=>'addCustomerEvent']);


CustomerAPIController.php

    public function addCustomer(Request $request, Account $account) {
        $cus = new Customer();
        $company = $account->company()->first();
        $validate = Validator::make($request->all(),$cus->validation($company),$cus->messages);
        if($validate->fails()) {
            return $this->apiResponse($request, ["success"=>false, "fields"=>$validate->errors()->keys(), "errorMessage"=>$validate->errors()->first() ]);
        }

    ...

    }

Test exception

CreateCustomerTest::agent_can_create_new_customer ErrorException: Trying to get property of non-object

/Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/app/Customer.php:68 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/app/Http/Controllers/CustomerApiController.php:264 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Controller.php:55 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:44 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Route.php:190 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Route.php:144 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Router.php:653 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Router.php:655 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Router.php:629 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Router.php:607 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:268 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:150 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:117 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:582 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:76 /Users/jamesllewellyn/PhpstormProjects/larascout5.3/scout-5.3/tests/customer/CreateCustomerTest.php:73

Line 68 of Customer.php I am trying to access the $company->id to use in my validation.

Line 264 of CustomerApiController.php is where I call Validator::make passing in the $company

Line 73 of CreateCustomerTest.php is the end of my JSON POST request

Any suggestions would be great as I'm totally stuck with this.

Thanks

James

0 likes
4 replies
Indemnity83's avatar

The problem appears to be in your Customer class on line 68 though; not in the controller; it doesn't appear to be getting to the line that deals with the account.

What does your Customer class look like, particularly whatever method includes line 68?

jamesllewellyn's avatar

Hi, thanks for the reply.

That's where I'm validating that the subaccount that I'm trying to add the new customer to belongs to the same company as the account.

    public function validation($company) {
        return [
            'subaccount_id' => 'required|exists:sites,id,company_id,' . $company->id,
            'first_name' => 'required',
            'last_name' => 'required',
            'email' => 'required|unique:customers,email|email',
            'line1' => 'required',
            'police_area' => 'required',
            'pool_user' => 'boolean',
            'phone_01' => 'required',
            'gender' => 'required',
            'days' =>'required',
            'month' =>'required',
            'years' =>'required'
        ];
    }

This line is 68 where the error is

            'subaccount_id' => 'required|exists:sites,id,company_id,' . $company->id,

because the company isn't getting found in the CustomerAPIController.php so the $company that's been passed into the validation is blank and doesn't have the id value that i'm trying to access, so I get a "Trying to get property of non-object" exception.

Indemnity83's avatar

Ok; which line in the CustomerApiController is 264? Sounds like it must be the validation line; just confirming.

Can you just add a couple die and dump checks? are you actually getting a null $account (I still suspect not).

What kind of relationship is the customer() method return in your Account model?

jamesllewellyn's avatar

Yeah CustomerApiController 264 is the validation line.

This is what I get if I die and dump the $account at the top of the method


App\Account {#2137
  #table: "accounts"
  #fillable: array:10 [
    0 => "peg_code"
    1 => "account_type"
    2 => "region"
    3 => "user_id"
    4 => "team"
    5 => "company_id"
    6 => "site_id"
    7 => "active"
    8 => "deleted"
    9 => "ref"
  ]
  #hidden: []
  #searchable: array:2 [
    "columns" => array:3 [
      "accounts.ref" => 7
      "accounts.peg_code" => 4
      "company.company_name" => 10
    ]
    "joins" => array:1 [
      "company" => array:2 [
        0 => "company.id"
        1 => "accounts.company_id"
      ]
    ]
  ]
  #connection: null
  #primaryKey: "id"
  #keyType: "int"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: []
  #original: []
  #relations: []
  #visible: []
  #appends: []
  #guarded: array:1 [
    0 => "*"
  ]
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  +exists: false
  +wasRecentlyCreated: false
  #search_bindings: []
}

This API method works fine when it's called from anywhere other than CreateCustomerTest.php.

Please or to participate in this conversation.