'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