Laravel Multi-Tenant Testing — Part 3

Josh Krawczyk
4 min readDec 10, 2018

--

Here we go again! I will be going over feature and unit tests for a multi-tenant application. It took me a while to actually get this working since I couldn’t find much material online. So I will be passing this knowledge onto you!

This article is part of a series. Check out the rest below!

Part 0 — Laravel Multi-Tenant App Setup

Part 1 — Laravel Passport and Hyn\Tenancy

Part 2 — VueJS and Laravel API

Part 3 — Laravel Multi-Tenant Testing←You are Here

You can find the full code example below. Make sure to use the Main branch.

I spent a long time trying to piece this all together. Granted this was my first experience writing tests, but adding in API authentication and per-tenant testing scenarios didn’t help. To solve this particular issue, I used testing examples from the hyn\multi-tenant package and various examples from the internet.

I could refine the tests a little more by not creating a tenant for every single test. As of right now it significantly increases the testing run time (Takes about a 1:20min to run)

Edit: I took the time to optimize the tests! Check here for the result.

Setup

Here is my directory structure.

To explain:

  • Endpoints — API Tests
  • Feature — Any application features (i.e Auth)
  • Scripts — OS level scripts to help with test cleanup
  • Traits — Traits supporting with testing 3rd party packages
  • Unit — Unit tests

We will need to update the phpunit.xml file to add some env variables and also add the Endpoints testing directory.

TicketFactory.php

Create a TicketFactory.php file in the database/factories directory. This will help with creating tickets for testing.

Database

Create a database named tenancy_test. This will be used when running tests and won’t affect your production database.

Supporting Traits

Here are some traits to help with testing Passport and Tenancy.

InteractsWithTenancy.php

I borrowed this from the hyn\multi-tenant package and made some modifications to fit my needs.

The setupTenancy() method is run during the test setup and creates the necessary tenant components. The setupHostnames() and setupWebsites() methods actually persistent the models to the database. And finally the activateTenant() method will set the current tenant as active.

InteractsWithPassport.php

I use this trait to override the Laravel API methods to attach the correct authentication headers. I call the createUserWithToken() method from within the tests.

Base Test Class

I created a base class for tenant tests that allows opportunities for the tests to create tenants.

Unit Tests

The only Unit test I have is one that tests the Middleware tenant identification. It just makes sure the tenant connection is set.

Feature Tests

Here I test the Laravel Auth functionality. These will extend the TenantTestCase Class

LoginTest.php

PasswordResetTest.php

RegistrationTest.php

Endpoint Tests

These tests will make sure the API is working like it should. It will utilize the InteractsWithPassport trait to simulate an authenticated user. The tests will also test if json values are returned.

TicketAPITest.php

Run Those Tests!

Every piece of code written comes down to the point. It is time to run the tests and pray for the green check marks. Run the command below

./vendor/bin/phpunit --testdox

And you should be something like this

If you are using mysql, you might get an error like:

PDOException: SQLSTATE[HY000]: General error: 1819 Your password does not satisfy the current policy requirements

You can set the password policy to LOW using this command

SET GLOBAL validate_password_policy=LOW;

Also note there is a script that will delete all of the tenant databases. I had a few hundred created by the time I actually got this working. I borrowed this one from the hyn\multi-tenant package also.

Just replace $password with your mysql root password (Assuming you are using MySQL)

Conclusion

That is it for the testing! Hopefully you were able to get the green check marks while testing in the demo or your own app. I might expand the demo a little more to include relations and more complex operations. I am still thinking about doing a graphql version of this also.

Thanks for reading!

--

--

Josh Krawczyk

Systems Engineer by day, Programmer by night. Just doing my best to juggle life, family, career, and passion.