Framework: Unable to unit testing Many to Many Relationship with assertInstanceOf method

Created on 1 Jun 2019  路  6Comments  路  Source: laravel/framework

  • Laravel Version: 5.8.19
  • PHP Version: 7.3.5
  • Database Driver & Version: libmysql - mysqlnd 5.0.12-dev - 20150407

Description:

Unable to testing Many to Many Relationship Assertion Failed :

Failed asserting that Illuminate\Database\Eloquent\Collection Object (...) is an instance of class "App\Tag".

Steps To Reproduce:

UnitThreadTest.php

namespace Tests\Unit;

use App\Tag;
use App\Thread;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ThreadTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function it_belongs_to_many_tags()
    {

        $thread = factory(Thread::class)->create();

        $this->assertInstanceOf(Tag::class, $thread->tags);

    }

}

2019_06_01_114457_create_threads_table.php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateThreadsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('threads', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('threads');
    }
}

2019_06_01_114508_create_tags_table.php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('tags');
    }
}

pivot table (2019_06_01_114720_create_tag_thread_table.php)

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTagThreadTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tag_thread', function (Blueprint $table) {
            $table->primary(['tag_id','thread_id']);
            $table->unsignedBigInteger('tag_id');
            $table->unsignedBigInteger('thread_id');

            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
            $table->foreign('thread_id')->references('id')->on('threads')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('tag_thread');
    }
}

Thread.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Thread extends Model
{
    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
}

Tag.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    public function threads()
    {
        return $this->belongsToMany(Tag::class);
    }
}

ThreadFactory.php

/* @var $factory \Illuminate\Database\Eloquent\Factory */

use App\Thread;
use Faker\Generator as Faker;

$factory->define(Thread::class, function (Faker $faker) {
    return [
        'title' => $faker->sentence,
        'body'  => $faker->paragraph
    ];
});

TagFactory.php

/* @var $factory \Illuminate\Database\Eloquent\Factory */

use App\Thread;
use Faker\Generator as Faker;

$factory->define(Thread::class, function (Faker $faker) {
    return [
        'name' => $faker->word
    ];
});

Note that the code alone will work but its test not.

Most helpful comment

You also have to create records in the pivot table, that's what the relationship is all about.

All 6 comments

Your test is incorrect. $thread->tags returns a collection of tags, not a single tag.

You can do something like this:

$this->assertInstanceOf(Tag::class, $thread->tags[0]);

@staudenmeir now:

ErrorException : Undefined offset: 0

Your test doesn't create any tags, so the relationship result is empty.

I dont think so that was the problem , with Tag factory :

public function it_belongs_to_many_tags()
{
      factory(Tag::class)->create();
      $thread = factory(Thread::class)->create();

      $this->assertInstanceOf(Tag::class, $thread->tags[0]);

}

same error:

ErrorException : Undefined offset: 0

You also have to create records in the pivot table, that's what the relationship is all about.

thanks i forgot about the pivot table, here is the solution maybe helps somebody :

public function it_belongs_to_many_tags()
{
    $tag = factory(Tag::class)->create();
    $thread = factory(Thread::class)->create();

    DB::table('tag_thread')->insert([
       'tag_id' => $tag->id,
       'thread_id' => $thread->id
    ]);

    $this->assertInstanceOf(Tag::class, $thread->tags[0]);

}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Fuzzyma picture Fuzzyma  路  3Comments

klimentLambevski picture klimentLambevski  路  3Comments

shopblocks picture shopblocks  路  3Comments

Anahkiasen picture Anahkiasen  路  3Comments

digirew picture digirew  路  3Comments