Philipp's avatar

How to test 'syncWithoutDetaching' function in phpunit

Whenever I create a new settlement I want to attach all current resources in the db to it - so here's all my code:

Models:

class Settlement extends Model
{
    public function resources()
    {
            return $this->belongsToMany(Resource::class)->withPivot('count');
    }
}
class Resource extends Model
{
    public function settlements()
    {
            return $this->belongsToMany(Settlement::class)->withPivot('count');
    }
}

store method on SettlementController:

/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required' 
        ]);

        $settlement = Settlement::create([
            'user_id'   => auth()->id(),
            'name'      => request('name')
        ]);

        $settlement->resources()->syncWithoutDetaching($settlement->getResourceIds());

        return redirect($settlement->path());
    }
public function getResourceIds()
    {
        return $resources = Resource::all()->pluck('id')->all();
    }

So everything is working as expected I just have no idea how to write a phpunit test for this case. Thanks!

0 likes
3 replies
bobbybouwmann's avatar
Level 88

Well I think a unit test is not the way to go here. A unit test tests the unit itself, however you want to test the database here and see if everything was added correctly.

Assuming you've setup factories in your application you can do something like this

public function testCreatingSettlementWithSyncedResources()
{
    $resources = factory(Resource::class, 2)->create();

    $this->post('settlement', [
        'name' => 'Settlement name',
    ]);

    $this->assertDatabaseHas('settlements', [
        'name' => 'Settlement name',
    ]);

    $settlement = Settlement::where('name', 'Settlement name')->first();

    foreach($resources as $resource) {
        $this->assertDatabaseHas('resource_settlement', [
            'resource_id' => $resource->id,
            'settlement_id' => $settlement->id,
        ]);
    }
}

Documentation: https://laravel.com/docs/5.6/database-testing#introduction

Also another small note, I wouldn't place the getResourcesIds in the Settlement model. Settlement shouldn't know all the resources, but only its own resources using the relationship. This should either me a helper method, repository or just a private method in your controller. Just my 2 cents ;)

Let me know if I can help you any further ;)

Philipp's avatar

okay I thought it would be okay because no matter how many resources there are a settlement should always have all of them attached.

I will make it a helper method though. :)

Thanks again for you help... test is running smooth!

bobbybouwmann's avatar

Great! If you have more questions you know where to find me ;)

Please or to participate in this conversation.