'How to test laravel controller method?
My controller looks like this:
public function store(Request $request) {
$validateData = $request->validate([
'name' => 'required|unique:languages',
'code' => 'required|size:3',
'flag' => 'required|size:2'
]);
$language = new Language();
$language->name = $request->name;
$language->code = $request->code;
$language->flag = $request->flag;
$saveLanguage = $language->save();
if(!$saveLanguage){
return response()->json(['error'=>'Something went wrong, please try later.'],500);
}
return response()->json(['success'=>'Language has been created successfully', 'data'=>$language],200);
As you can see, I am instantiating a new Language object and everything works fine, but first problem is, imagine I change Language class in future (for example: you have to pass 2 parameters in constructor), I have to change this controller and every other controllers where I am instantiating Language
object.
The second problem is I can't or it's too hard to test this controller.
I am curious what is the best solution to solve this problems in laravel?
For example is it a good solution to use simple factory or factory method pattern for every model I am using in my controllers.
I think when you write something like this $var = new SomeClass()
in other class, this otherClass
is depends on SomeClass and when you want to change SomeClass
you have to update otherClass
to. What do you think abaout this, how can I avoid this.
Solution 1:[1]
Or you could use the Eloquent Create
function, this way you don't have to worry about the constructor.
$language = Language::create($request->only(['name', 'code', 'flag']));
This function will insert the data in the database and return the model.
Solution 2:[2]
Problem #1: If you change the signature of a constructor (e.g. adding new required parameters to the Language
class constructor), then yes, you'll need to update all places where that constructor is called. There's no way around that, unless you can encapsulate the logic for what those parameters should be into a helper method somewhere (though you'll still need to update all calls the first time, while future changes will be abstracted away). However, modern IDEs (e.g. PHPStorm) can help you automate the process of replacing the old signature with the new signature.
Problem #2: You can actually test a controller like this quite easily. To take an example from the Laravel docs and apply it to your code, you could do something like this (in Laravel 7.x):
$response = $this->postJson('/language', ['name' => 'Swedish', 'code' => 'swe', 'flag => 'SE']);
$response
->assertStatus(200)
->assertJson([
'success' => 'Language has been created successfully',
])
->assertJsonPath('data.name', 'Swedish')
->assertJsonPath('data.code', 'swe')
->assertJsonPath('data.flag', 'SE');
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Jerodev |
Solution 2 | eldilibra |