Laravel: Several methods of writing Unit Test for super difficult cases

Tram Ho

During the process of writing Unit Test for projects, you will inevitably encounter some extremely difficult Unit Test cases, either you have to refactor a lot, or have to switch to writing Feature Test. But the Feature Test doesn’t always work, for example, you need to write tests for Jobs or Models.

Here are some of the cross tests I encountered, note below for easy to find later

Unit Test when Model calls a static function

Here is your Controller:

In fact, when running Unit Test with a static function call like this, the model will directly query to the Database, making the data retrieved is real data, not fake data using Mockery, making your test not. can run.

The solution to this problem is as follows:

Unit Test

By using keyword alias , you will allow the newly mocked Post object to overwrite the Post object in the controller and don’t forget the two comment lines at the beginning of the function, those two comment lines will help you avoid the error “Object was created”. .

In some cases the way above doesn’t work, you can create a mock as usual then inject it into the Service Container, forcing it to replace the real Object Post that is being used:

Unit Test with callback function

Let’s look at a query like this:

As in the above example, the second parameter of whereHas is a callback function, in case if you only shouldReceive("whereHas") then the query line inside the callback will not be tested. Now, let’s test this callback:

Using with to fake the second parameter to whereHas function, because this parameter is a callback I use Mocker::on() to create a similar callback, the default parameter of this callback is $closure , If you dd($closure) , you should see something like this

This is a fake closure created by Mockery, it has the same structure as the closure of whereHas function, with the default parameter also a query builder. Therefore, we need to pass the variable $builder into the closure of $ closure. The explanation is a bit abstract and confusing noodles, but roughly it helps to fake the query inside that callback.?♂

Unit Test with an array of callback functions

This is the case when you query with the with() above all else, the typical example would look like this: fetching a list of comments on a post.

In this case we will also handle using Mockery::on() to fake a callback to the with() function, but with a slight change like this:

At this point $closure not an instance of the callback function anymore, but an array of instances, so you need to point to the correct closure of comments by pointing to the key ‘comments’ as above, and then pass in the query. builder as usual. With return we will check if $ closure with the current key is the correct callback, because maybe Mockery will loop through many different closures, so we need to check with the correct closure of comments to return the result. fruit.

Some other cases

Unit Test with callback in the collection

Consider the following example:

Actually, the test cases with the collection are very simple, as long as the input of the collection methods is valid, the test in the collection will run by default. For example, if your query returns a fake value, the map () function will automatically be tested, if you fake the return value is empty, the map () function will not be tested, as follows:

Like this, map () will not be tested, let’s return a collection with the same structure as the results returned from the real query, the best way is to use the factory as follows:

This is done?

Similar to collection methods with other callbacks like filter (), reduce (), …

Unit Test with query in the loop

Consider the following example again:

Actually, this case is not complicated, you do not need to use the loop in Unit Test, just write the test as usual.

However, be careful when there are more complex queries in a loop, you may also consider refactoring the code if there are too many problems to be resolved.

Fake auth user for the request

In some cases you need to use the login credentials to do something, for example, in unit test you can do the following to fake a login case for the user:

Unit Test

In the above case, because the get () function accepts the Request parameter, you can set the auth user for the request, but in the case the function does not take the request parameter but use the facade request() to get the login information. so what?

Now we need to overwrite the instance request running in the service container with our fake request, like so:

It is done!

Final

There are many more difficult tests that I can not mention all, after I encounter any more difficult cases, I will definitely write an additional article. Thank you for reading the article!

Share the news now

Source : Viblo