I am trying to write a testcase which tests the association and detachment of the relationship between two Eloquent models in Laravel 4.2
Here's my test case:
class BookingStatusSchemaTest extends TestCase
{
private $statusText = "Confirmed";
private $bookingStub;
private $statusStub;
public function testMigrateService()
{
$this->createTestData();
$booking = $this->bookingStub;
$status = $this->statusStub;
/**
* Check that the booking has no status. OK
*/
$this->assertNull($booking->status);
/**
* Check that status has no booking. OK
*/
$this->assertEquals(count($status->bookings), 0);
/**
* Add a status to the booking. OK
*/
$booking->status()->associate($this->statusStub);
/**
* Check that status has a booking. NOT OK - This gives error
*/
$this->assertEquals(count($status->bookings), 1);
/**
* Check that the booking has a status. OK
*/
$this->assertNotNull($booking->status);
/**
* Do NOT delete the status, just set the reference
* to it to null.
*/
$booking->status = null;
/**
* And check again. OK
*/
$this->assertNull($booking->status);
}
private function createTestData()
{
$bookingStatus = BookingStatus::create([
'status' => $this->statusText
]);
$booking = Booking::create([ ]);
$this->bookingStub = $booking;
$this->statusStub = $bookingStatus;
}
}
When I execute it I get:
There was 1 failure:
1) BookingStatusSchemaTest::testMigrateService
Failed asserting that 1 matches expected 0.
Booking model:
class Booking extends Eloquent {
/**
* A booking have a status
*/
public function status()
{
return $this->belongsTo('BookingStatus');
}
}
BookingStatus Model:
class BookingStatus extends Eloquent
{
protected $table = 'booking_statuses';
protected $guarded = [ 'id' ];
protected $fillable = ['status'];
/**
* A booking status belongs to a booking
*/
public function bookings()
{
return $this->hasMany('Booking');
}
}
Here's the migration Schema for bookingstatus:
Schema::create('booking_statuses', function(Blueprint $table)
{
$table->increments('id');
$table->string('status');
$table->timestamps();
});
And heres for booking:
Schema::create('bookings', function(Blueprint $table)
{
$table->increments('id');
$table->unsignedInteger('booking_status_id')->nullable();
$table->timestamps();
});
What do I have to add / change to be able to verify the relationship in my test case?
$testBooking->statusis never null, it's an Illuminate\Support\Collection - that's what you get when you access a relationship as a property. A collection is never null, but it can be empty, you can check this with$testBooking->status->isEmpty()(returns boolean) or just treat it like an array:$this->assertCount(0, $testBooking->status);.echo $testBooking->status->status;givesConfirmed, so I don't think it's deleted..createTestDatait looks like you expect the id to be returned from thesave()-method - that's not the case,save()returns a boolean indicating if everything went fine. In your case it didn't blow up yet because the boolean is probably casted to 1 within thefind()-method. Could you please do avar_dump($this->bookingId, $this->statusId)in the test-method to check that. Not sure if this is the culprit, but you should fix it anyway. Did that change anything?bookings-table should hold the foireign key 'booking_status_id' and should definitely not cascade on delete - if you delete a booking, you do not want to delete the related status, because other bookings may be associated with that status. So:BookingbelongsToBookingStatus, andBookingStatushasManyBooking(belongsToManymight sound more natural, but that's for many-to-many-relationships).createTestData()method. They were loaded with the properties at that time. 1.) you have tosave()the booking after you associated the status to persist the change. 2.) You have to "reload" (i.e. fetch a new instance of) your$status, e.g. with$status = BookingStatus::first();to get the bookings, or at least trigger a new query to fetch the bookings:$status->load('bookings');or$status->bookings()->get(). And 3.) You would (hopefully) never do things like this in a real application!