У меня очень странное поведение с PHPUnit в laravel.У меня есть тест invoices_are_split_between_extensions
, который создает несколько расписаний с записями и контракт, в котором есть специальное условие, которое необходимо проверить.
Я собрал все необходимые функции в одну функцию, выполняющую тест в качестве примера.
/** @test */
public function invoices_are_split_between_extensions()
{
$user = $this->user();
$contract = factory(Contract::class)->states('complete')->create([
'user_id' => $user->id
]);
$extension = factory(ContractExtension::class)->create([
'contract_id' => $contract->id,
'start' => '2018-01-01',
'end' => '2018-01-15',
'sp' => '50',
'pp' => '40',
]);
$extension2 = factory(ContractExtension::class)->create([
'contract_id' => $contract->id,
'start' => '2018-01-16',
'end' => '2018-01-31',
'sp' => '50',
'pp' => '40',
]);
$timesheet = factory(Timesheet::class)->create([
'user_id' => $user->id,
'customer_id' => $contract->customer_id,
'contract_id' => $contract->id,
'extension_id' => $extension->id,
'total' => 16,
'date' => '2018-01-01',
]);
$entry = factory(TimesheetEntry::class)->create([
'date' => '2018-01-14',
'value' => 8,
'user_id' => $user->id,
'tariff_id' => 1,
'contract_id' => $contract->id,
'customer_id' => $contract->customer_id,
'extension_id' => $extension->id,
'timesheet_id' => $timesheet->id,
'invoiced' => false,
]);
$entry1 = factory(TimesheetEntry::class)->create([
'date' => '2018-01-15',
'value' => 8,
'user_id' => $user->id,
'tariff_id' => 1,
'contract_id' => $contract->id,
'customer_id' => $contract->customer_id,
'extension_id' => $extension->id,
'timesheet_id' => $timesheet->id,
'invoiced' => false,
]);
$entry2 = factory(TimesheetEntry::class)->create([
'date' => '2018-01-16',
'value' => 4,
'user_id' => $user->id,
'tariff_id' => 1,
'contract_id' => $contract->id,
'customer_id' => $contract->customer_id,
'extension_id' => $extension2->id,
'timesheet_id' => $timesheet->id,
'invoiced' => false,
]);
$invoices = Invoice::fromTimesheet($timesheet);
$this->assertCount(2, $invoices);
$this->assertEquals(800, $invoices[0]->total);
$this->assertEquals(200, $invoices[1]->total);
$this->assertEquals($extension->id, $invoices[0]->extension_id);
$this->assertEquals($extension2->id, $invoices[1]->extension_id);
}
Этот тест выдает ошибку ErrorException: Trying to get property 'id' of non-object
1) Tests\Feature\InvoiceTest::invoices_are_split_between_extensions
ErrorException: Trying to get property 'id' of non-object
/home/ilyas/script/clockwork/contract-module/src/Models/Contract.php:435
/home/ilyas/script/clockwork/timesheet-module/src/Models/Timesheet.php:293
/home/ilyas/script/clockwork/app/src/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1011
/home/ilyas/script/clockwork/app/src/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Collection.php:261
/home/ilyas/script/clockwork/timesheet-module/src/Models/Timesheet.php:303
/home/ilyas/script/clockwork/invoice-module/src/Models/Invoice.php:272
/home/ilyas/script/clockwork/app/src/tests/Feature/InvoiceTest.php:145
Когда я перехожу к строке 435 в Contract.php
, я нахожу следующую строку.Где $tariff->id
в соответствии с ошибкой, а не объектом.
$override = $this->tariffs->where('id', $tariff->id)->first()->pivot->sp ?? null;
После быстрого dd()
я обнаружил, что это объект, экземпляр Tariff
, называемый Tariff::findOrFail($key);
, возвращаетдопустимый красноречивый объект.Теперь начинается самое интересное.Если я получу идентификатор как $tariff['id']
, это сработает.Если я пытаюсь что-то вроде $tariff->toArray()
, я получаю ошибку Error: Call to a member function toArray() on null
.
$tariff = $tariff->toArray();
$override = $this->tariffs->where('id', $tariff['id'])->first()->pivot->sp ?? null;
Если я dd()
$ тарифицирую до toArray()
, я получаю коллекцию Eloquent.Если я dd()
после $override
, я получаю ту же коллекцию, что и массив.Если я удаляю dd()
, ошибка появляется снова ... Это сводит меня с ума на несколько часов.
Я легко могу исправить эту функцию с помощью tariff['id']
, но я узнал, что может быть причиной этой проблемы.