CRUD Unit Testing in Laravel 5

Recently, I started an open source e-commerce application called LARACOM made with Laravel together with Rob Gloudemans’ shopping cart and other related e-commerce packages.

When starting this project, I have to think of the long term so never in my mind that I will not use the TDD (test driven development) approach, it is a MUST. So in doing it, I need my tests to be separated in two different groups, one for Unit testing and one for Feature testing.

Unit testing is testing your classes — Models, Repositories etc. while Feature testing is testing your code if it hits the controllers and asserting the actions it will throw, say a redirect, returns a view or redirect with error flash messages.

Enough with the introduction. If you haven’t tried TDD before, I have written a basic TDD approach in here. I will not talk about the basic already since there is already an article for it.

What I will do today is doing a Carousel for my e-commerce project.

Edit: Hey! I created a base repository package you can use for your next project :)

Part I: Positive Unit Testing

Let’s start with the CREATE test.

Create the file /tests/Unit/Carousels/CarouselUnitTest.php

What are we trying to do in this file:

  • See if our repository class can take this data parameters and actually create the carousel in the database
  • See if after creating the carousel, the response have the same values as the parameters we feed it in

Now, in your terminal, run vendor/bin/phpunit (you must be in the root directory of your application)

Is it an error? Yes! It should be since we have not created the files it is trying to use.

PHPUnit 6.5.7 by Sebastian Bergmann and contributors.E                                                                   1 / 1 (100%)Time: 700 ms, Memory: 26.00MBThere was 1 error:1) Tests\Unit\Carousels\CarouselUnitTest::it_can_create_a_carousel
Error: Class 'Tests\Unit\Carousels\CarouselRepository' not found

So we need to solve the error by creating the CarouselRepository file.

Let’s create it in app/Shop/Carousels/Repositories/CarouselRepository.php

Obviously, you cannot find the Shop and Carousels folder in the default Laravel installation. You can do your own way on how to structure your folder but I’d love to do it this way. You just have to namespace it properly.

We also created a specific error exception file here.

Create it in, app/Shop/Carousels/Exceptions folder otherwise it will throw an error.

In this repository, we use dependency injection. We inject the class to the repository so it can use it. The Carousel model would throw also an error here since it is not yet existing.

We create it first: app/Shop/Carousels/Carousel.php

After the repository is created, import it to our test file like so:

and run again vendor/bin/phpunit

Error? Yes? Yup. You guessed it right.

PHPUnit 6.5.7 by Sebastian Bergmann and contributors.E                                                                   1 / 1 (100%)Time: 898 ms, Memory: 26.00MBThere was 1 error:1) Tests\Unit\Carousels\CarouselUnitTest::it_can_create_a_carousel
App\Shop\Carousels\Exceptions\CreateCarouselErrorException: PDOException: SQLSTATE[HY000]: General error: 1 no such table: carousels in /Users/jsd/Code/shop/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:77

It is trying to insert the data into the database but the table is not yet created. What do we need now? Migration file.

In your terminal, run:

php artisan make:migration create_carousels_table --create=carousels

Once it is created, open it and configure the columns you need.

The link is nullable but definitely the title and the image src are required.

Once this is done, run vendor/bin/phpunit again.

Well done mate, well done.

PHPUnit 6.5.7 by Sebastian Bergmann and contributors..                                                                   1 / 1 (100%)Time: 696 ms, Memory: 26.00MBOK (1 test, 6 assertions)

You already have one test passing. So, as long as this test passes whenever you run vendor/bin/phpunit, you can be confident that the application can create a carousel slider always.

Show the carousel after it is created

Now, lets try to test the READ.

See if we can see the carousel once it is created.

Again, run the test. Every test we newly created, we always expect a failed test. Why? It is because we have not yet done any implementation. If we get a success after we create the test, then you are doing it WRONG.

Note: Every test we create should be at the top as we want it to be run first

PHPUnit 6.5.7 by Sebastian Bergmann and contributors.E                                                                   1 / 1 (100%)Time: 688 ms, Memory: 26.00MBThere was 1 error:1) Tests\Unit\Carousels\CarouselUnitTest::it_can_show_the_carousel
InvalidArgumentException: Unable to locate factory with name [default] [App\Shop\Carousels\Carousel].

With this error, it is looking for the model factory for the Carousel.

So, we need to create it in: database/factories/CarouselModelFactory.php

Run the phpunit again.

PHPUnit 6.5.7 by Sebastian Bergmann and contributors.E                                                                   1 / 1 (100%)Time: 708 ms, Memory: 26.00MBThere was 1 error:1) Tests\Unit\Carousels\CarouselUnitTest::it_can_show_the_carousel
Error: Call to undefined method App\Shop\Carousels\Repositories\CarouselRepository::findCarousel()

Yup. The factory error is now gone. Meaning it can now persist in the database. Others, they want persistence to be separate so you can put in your test instead of :

$carousel = factory(Carousel::class)->create();

then

$carousel = factory(Carousel::class)->make();

But we still have an error, it can’t find the findCarousel() method in the repository class. We create that method.

Self explanatory file. Run the phpunit and see the output.

PHPUnit 6.5.7 by Sebastian Bergmann and contributors..                                                                   1 / 1 (100%)Time: 932 ms, Memory: 26.00MBOK (1 test, 6 assertions)

Pat on the back mate. Good job.

Update Carousel test

Now, see if we can UPDATE the carousel

In here, we use again the model factory to create the carousel the we pass $data parameters to update the created carousel and assert if we can get the same values in the update $data parameters.

This will fail as you know because the updateCarousel method is not yet created so we create it.

Once this method is created, run phpunit again.

PHPUnit 6.5.7 by Sebastian Bergmann and contributors..                                                                   1 / 1 (100%)Time: 932 ms, Memory: 26.00MBOK (1 test, 6 assertions)

It just work out of the box!

Finally, we test the delete

Create a test if we can delete the carousel we created.

Then create the deleteCarousel() method

When this method is hit, it should return a boolean response. True if successfully delete else null. Then run phpunit again.

➜ git: phpunit --filter=CarouselUnitTest::it_can_delete_the_carousel
PHPUnit 6.5.7 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)Time: 916 ms, Memory: 26.00MBOK (1 test, 1 assertion)

WOW. You have made it here! CONGRATULATIONS!

If you want to see tests live in action, heads up to my Unit Tests here

###

As a PART II, let us do NEGATIVE testing!

/jsd

Senior Fullstack Engineer

Senior Fullstack Engineer