Home > database >  Passing parameters in an Unit Test, function update in database CRUD Laravel
Passing parameters in an Unit Test, function update in database CRUD Laravel

Time:04-04

I've been creating some tests to try my create delete edit functions on laravel from my database, this is my code:

ConstituencyController.php :

<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreConstituencyRequest;
use App\Http\Resources\ConstituencyResource;
use App\Models\Constituency;
use Illuminate\Http\Request;
use phpDocumentor\Reflection\Types\Collection;

class ConstituencyController extends Controller
{


    /**
     * Display a listing of the constituencies.
     *
     *
     */
    public function index()
    {
        $constituency = Constituency::all();

        return ConstituencyResource::collection($constituency);
    }



    /**
     * Show the form for creating a new resource.
     *
     *
     */
    public function create()
    {
        //
    }



    /**
     * Store a newly created constituency in storage.
     *
     * @param Request $request
     *
     */
    public function store(Request $request)
    {
        $name = $request->name;
        $data = array("name"=>$name);

        Constituency::insert($data);
    }



    /**
     * Display the specified constituency.
     *
     * @param  int $id
     *
     */
    public function show(int $id)
    {
        $constituency = Constituency::find($id);

        return new ConstituencyResource($constituency);
    }



    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     *
     */
    public function edit(int $id)
    {
        //
    }



    /**
     * Update the specified constituency in storage.
     *
     * @param Request $request
     * @param  int  $id
     *
     */
    public function update(Request $request, int $id)
    {
        $constituency = Constituency::find($id);
        $constituency->name = $request->name;

        $constituency->update();
    }



    /**
     * Remove the specified constituency from storage.
     *
     * @param  int  $id
     *
     */
    public function destroy(int $id)
    {
        Constituency::find($id)->delete();
    }
}

Constituency.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Constituency extends Model
{
    use HasFactory;

    public function candidate()
    {
        return $this->hasMany(Candidate::class);
    }

    public function town()
    {
        return $this->hasMany(Town::class);
    }
}

ConstituencyResource.php :

    <?php
    
    namespace App\Http\Resources;
    
    use Illuminate\Http\Resources\Json\JsonResource;
    
    class ConstituencyResource extends JsonResource
    {
        /**
         * Transform the resource into an array.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
         */
        public function toArray($request)
        {
            return [
                'id' => $this->id,
                'name' => $this->name,
                'created_at' => $this->created_at,
                'updated_at' => $this->updated_at,
            ];
        }
    
    
    }

ConstituencyFactory.php :

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Constituency>
 */
class ConstituencyFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'name' => $this->faker->word(),
        ];
    }
}

Now this is my test to update a constituency:

public function test_a_constituency_can_be_modified()
    {
        $constituency = Constituency::factory()->create();
        $constituency_id = $constituency->id;

        $response = $this->put('api/constituencies/'.$constituency_id);

        $this->assertDatabaseHas('constituencies', [
            'id' => $constituency->id,
            'name' => $constituency->name,
            'created_at' => $constituency->created_at,
            'updated_at' => $constituency->updated_at,
        ]);
    }

Now of course the test passes, but i'm not actually giving it some new parameters to change... I've been trying to give some parameters to the function to actually change some data but i can't figure out how to do that.... I don't think i'm gonna have to put the parameters in the URI but where then?

CodePudding user response:

If you are using PHPUnit you likely want to make use of Data Providers:

Example from docs

/**
 * @dataProvider additionProvider
 */
public function testAdd(int $a, int $b, int $expected): void
{
    $this->assertSame($expected, $a   $b);
}

public function additionProvider(): array
{
    return [
        'adding zeros'  => [0, 0, 0],
        'zero plus one' => [0, 1, 1],
        'one plus zero' => [1, 0, 1],
        'one plus one'  => [1, 1, 3]
    ];
}

The smart folks over at Tighten also have an excellent tutorial on data providers.

If you're using PEST then you'll want Data Sets.

Example from docs

dataset('emails', [
    '[email protected]',
    '[email protected]'
]);

it('has emails', function ($email) {
    expect($email)->not->toBeEmpty();
})->with('emails');  // <-- use the dataset

Using data providers and data sets allows you to reuse data, but also test against multiple inputs for your unit test. You could if you wanted just hard code a value after you're arrange statement (where you create the DB record) but that has limitations and providers are far more flexible.

Update - Example test

The following is an example of how you might go about things. Note this is not exhaustive and things like using $request->all() to update your model are not advisable but I have done so to keep things simple for illustritive purposes. This should give you an idea of where/how you could go about performing your testing. There are many ways/opinions on such things.

api.php

Route::put('/constituencies/{constituency}', 
    [ConstituencyController::class, 'update']
)->name('api.constituencies.update');

ConstituencyController.php

<?php

namespace App\Http\Controllers;

use App\Models\Constituency;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ConstituencyController extends Controller
{
    public function update(Request $request, Constituency $constituency)
    {
        $constituency->update($request->all());

        return response()->json($constituency, Response::HTTP_OK);
    }
}

ExampleTest.php

<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\Constituency;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @test
     * @dataProvider constituencyNameProvider
     * @return void
     */
    public function it_can_update_constituency_name_successfully($constituencyName)
    {
        // Arrange
        $constituency = Constituency::factory()->create();
        $payload = ['name' => $constituencyName];

        // Act
        $response = $this->put(route('api.constituencies.update', $constituency->id), $payload);

        // Assert
        $response->assertStatus(Response::HTTP_OK)
            ->assertJson([
                'id' => $constituency->id,
                'name' => $constituencyName
            ])
            ->assertJsonStructure([
                'id', 'name', 'created_at', 'updated_at'
            ]);
    }

    public function constituencyNameProvider(): array
    {
        return [
            ['Ostwald'],
            ['Springtown'],
            ['Baybarrow'],
            ['Blackhaven'],
            ['Lochspring'],
        ];
    }
}
  • Related