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'],
];
}
}