Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unit test for relationship in laravel Model

I am new for laravel model unit testing.so please look and suggest me what i am doing wrong.my code is given below.I have 2 models User and UserState.

Model User

public function state()
    {
        return $this->hasOne('UserState');
    }

Model UserState

public function user()
{
    return $this->belongsTo('User');
}

now i am writing unit test for UserState. which is given below :

UnitTest UserStateModelTest

public function testUserRelationIsTrue(){
    $user = new User();
    $user->username = 'testusername';
    $user->save();
    $this->assertEquals($user->user_id, $user->state->id);
}

during test run by phpunit it generate error

Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation:
1452 Cannot add or update a child row: a foreign key constraint fails
like image 250
Rajawat Avatar asked Jul 28 '14 08:07

Rajawat


2 Answers

If you really want to test a relationship method, you can do it without even saving a model to the database. You still need to use the RefreshDatabase trait (or the DatabaseMigrations trait) or else the models won't be mapped to any table.

# tests/Unit/ParentTest.php
/**
 * Test Parent has HasMany relationship with Child model
 * @test
 */
public function has_many_children_with_parent_id_fk()
{
    $parent = new Parent;
    $foreign_key = 'parent_id';

    // Get the relationship object, not the data collection
    $relationship = $parent->children();
    $related_model = $relationship->getRelated();

    // Assert this is a HasMany relationship
    $this->assertInstanceOf(HasMany::class, $relationship);
    // Assert the related model is Child
    $this->assertInstanceOf(Child::class, $related_model);
    // Assert the foreign key is the one we specified
    // (This can be useful if you do not use the default one)
    $this->assertEquals($foreign_key, $relationship->getForeignKeyName());
    // Assert the foreign key is a column
    // of the database table mapped by the Child model
    $this->assertTrue(Schema::hasColumns($related_model->getTable(), array($foreign_key)));
}
# tests/Unit/ChildTest.php
/**
 * Test Child has belongsTo relationship with Parent model
 * @test
 */
public function belongs_to_parent_with_parent_id_fk()
{
    $child = new Child;
    $foreign_key = 'parent_id';

    // Get the relationship object, not the data collection
    $relationship = $child->parent();
    $related_model = $relationship->getRelated();

    // Assert this is a BelongsTo relationship
    $this->assertInstanceOf(BelongsTo::class, $relationship);
    // Assert the related model is Parent
    $this->assertInstanceOf(Parent::class, $related_model);
    // Assert the foreign key is the one we specified
    // (This can be useful if you do not use the default one)
    $this->assertEquals($foreign_key, $relationship->getForeignKeyName());
    // Assert the foreign key is a column
    // of the database table mapped by the Child model
    $this->assertTrue(Schema::hasColumns($relationship->getParent()->getTable(), array($foreign_key)));
}

This is a bit of a handful but you can make a custom assertion to encapsulate all of this in the TestCase all tests files extend. The following methods suited my needs

# tests/TestCase.php
public function assertHasManyUsing($related_model, $relationship, $foreign_key)
{
    $this->assertInstanceOf(HasMany::class, $relationship);
    $this->assertInstanceOf($related_model, $relationship->getRelated());
    $this->assertEquals($foreign_key, $relationship->getForeignKeyName());
    $this->assertTrue(Schema::hasColumns($relationship->getRelated()->getTable(), array($foreign_key)));
}

public function assertBelongsToUsing($related_model, $relationship, $foreign_key)
{
    $this->assertInstanceOf(BelongsTo::class, $relationship);
    $this->assertInstanceOf($related_model, $relationship->getRelated());
    $this->assertEquals($foreign_key, $relationship->getForeignKeyName());
    $this->assertTrue(Schema::hasColumns($relationship->getParent()->getTable(), array($foreign_key)));
}

And now, refactoring the tests look like this

# tests/Unit/ParentTest.php
/**
 * Test Parent has HasMany relationship with Child model
 * @test
 */
public function has_many_children_with_parent_id_fk()
{
    $parent = new Parent;

    $this->assertHasManyUsing(Child::class, $parent->children(), 'parent_id');
}
# tests/Unit/ChildTest.php
/**
 * Test Child has belongsTo relationship with Parent model
 * @test
 */
public function belongs_to_parent_with_parent_id_fk()
{
    $child = new Child;

    $this->assertBelongsToUsing(Parent::class, $child->parent(), 'parent_id');
}
like image 99
IGP Avatar answered Sep 30 '22 17:09

IGP


Argument #1 of PHPUnit\Framework\Assert::assertInstanceOf() must be a class or interface name

tests\TestCase.php:14

>      10▕     use CreatesApplication;
>      11▕
>      12▕     public function assertHasManyUsing($related_model, $relationship, $foreign_key)
>      13▕ {  
>   ➜ 14▕     $this->assertInstanceOf(HasMany::class, $relationship);     
>      15▕     $this->assertInstanceOf($related_model, $relationship->getRelated());
>      16▕     $this->assertEquals($foreign_key, $relationship->getForeignKeyName());
>      17▕     $this->assertTrue(Schema::hasColumns($relationship->getRelated()->getTable(),
> array($foreign_key)));
>      18▕ }
like image 28
TestKunde Avatar answered Sep 30 '22 17:09

TestKunde