Masonite testing is very simple. You can test very complex parts of your code with ease by just extending your class with a Masonite unit test class.
Although Masonite uses pytest
to run tests, Masonite's test suite is based on unittest
. So you will use unittest
syntax but run the tests with Pytest. Because of this, all syntax will be in camelCase
instead of PEP 8 under_score
. Just know that all TestCase
method calls used during testing is in camelCase
form to maintain unittest standards.
Normal tests should still be underscore and start with test_
though like this:
First, create a new test class in a testing directory. There is a craft command you can run to create tests for you so just run:
This will create a user test for us which we can work on. You can drag this test in any subdirectory you like.
This command will create a basic test like the one below:
That's it! You're ready to start testing. Read on to learn how to start building your test cases.
Most times you want to develop and test on different databases. Maybe you develop on a local MySQL database but your tests should run in a SQLlite database.
You can create a .env.testing
file and put all database configs in that. When Pytest runs it will additionally load and override any additional environment variables.
Your .env.testing
file may look like this:
Feel free to load any testing environment variables in here. By default they will not be commited.
Here is a list of methods that can be used for assetions.
All methods that begin with assert
can be chained together to run through many assertions. All other method will return some kind of boolean or value which you can use to do your own assertions.
We have a few options for testing our routes.
To check if a route exists, we can simple use either get or post:
The request and responses of a test are gotten by accessing the request
and response
attributes. The response
attribute will be a string representation of your route:
You can choose anyone of the normal request methods:
You can use a standard JSON request and specify whichever option you need using the json()
method:
This can be used to see if the template returned a specific value
You can also use:
You can easily check if the response is ok by using the ok
method:
By default, all calls to your routes with the above methods will be without CSRF protection. The testing code will allow you to bypass that protection.
This is very useful since you don't need to worry about setting CSRF tokens on every request but you may want to enable this protection. You can do so by calling the withCsrf()
method on your test.
This will enable it on a specific test but you may want to enable it on all your tests. You can do this by adding the method to your setUp()
method:
As you have noticed, Masonite has exception handling which it uses to display useful information during development.
This is an issue during testing because we wan't to be able to see more useful testing related issues. Because of this, testing will disable Masonite's default exception handling and you will see more useful exceptions during testing. If you want to use Masonite's built in exception handling then you can enable it by running:
You can get the output by using the capture output easily by calling the captureOutput
method on your unit test:
A lot of times you will want to build tests around your API's. There are quite a few methods for testing your endpoints
You can test to make sure your endpoint returns a specific amount of something. Like returning 5 articles:
You can also use assertCount(5)
:
You can also use amount
which is just an alias for count
:
You can also check if a specific JSON key has a specific amount. For example:
Sometimes you will want to check if your endpoint returns some specific JSON values:
You can also specify a dictionary of values as well and will check if each value inside the response:
You do not have to specify all of the elements. Just the ones you want to check for.
You can alo use:
You can also assert values inside a list of responses:
You can also use dot notation for multi dimensional endpoints:
Sometimes you don't want to use dot notation and may choose to convert directly to a dictionary and assert values on that. This is also good for debugging so you can print the dictionary to these terminal. You can do this easily:
You can test if a specific parameter contains a specific value. For example if you want to see if the parameter id
is equal to 5
:
You can test if a specific header contains a specific value. For example if you want to see if the header Content-Type
is equal to text/html
:
You can use the isStatus
and assertIsStatus
methods to assert status checks:
You can also easily assert 404
methods:
This is the same as asserting a 404
status code.
By default, Masonite turns off subdomains since this can cause issues when deploying to a PaaS that deploys to a subdomain like sunny-land-176892.herokuapp.com
for example.
To activate subdomains in your tests you will have to use the withSubdomains()
method. You can then set the host in the wsgi
attribute.
By default, to prevent messing with running databases, database test cases are set to only run on the sqlite
database. You can disable this by setting the sqlite
attribute to False
.
This will allow you to use whatever database driver you need.
By default, all your tests will run inside a transaction so any data you create will only exist within the lifecycle of the test. Once the test completes, your database is rolled back to its previous state. This is a perfect way to prevent test data from clogging up your database.
Although this is good for most use cases, you may want to actually migrate and refresh the entire migration stack. In this case you can set the refreshes_database
attribute to True
.
Now this will migrate and refresh the database.
Beware that this will destroy any database information you have.
Factories are simply ways to seed some dummy data into your database. You can create a factory by making a method that accepts a faker argument and using that to seed data.
Masonite has a convenient method you can use that will run once the test first boots up called setUpFactories
. This will run once and only once and not between every test.
Let's create the factory as well as use the setUpFactories method to run them now.
Below is how to create 100 users:
You don't need to build factories though. This can be used to simply create new records:
We can load users into the route and check if they can view the route. This is good to see if your middleware is acting good against various users. This can be done with the acting_as()
method.
Maybe you need to check a post request and pass in some input data like submitting a form. You can do this by passing in a dictionary as the second value to either the get
or post
method:
The same can be applied to the get method except it will be in the form of query parameters.
Instead of doing model calls to check if values exist in the database, you can use a simple assertDatabaseHas
assertion:
You can also do the same thing with the opposite assertDatabaseNotHas
assertion:
To complete our test, let's check if the user is actually created:
Thats it! This test will now check that the user is created properly
You can run tests by running:
assertContains(value)
assertHasAmount(amount)
assertHeaderIs(key, value)
assertNotFound()
assertNotHasAmount(amount)
assertPathIs(value)
assertHasJson(key, value)
assertParameterIs(parameter, value)
isNamed(name)
assertJsonContains(key, value)
assertIsStatus(code)
hasMiddleware(*middleware)
assertCount(number)
assertHasHeader(name)
assertNotHasHeader(name)
hasController(name)
contains(value)
ok()
canView()
hasJson(key, value)
count(number)
amount(number)
isGet()
isPost()
isPut()
isPatch()
isDelete()
hasSession(key, value)
parameterIs()
headerIs()