Testing

    Lumen is built with testing in mind. In fact, support for testing with PHPUnit is included out of the box, and a file is already setup for your application. The framework also ships with convenient helper methods allowing you to expressively test your application's JSON responses.

    An ExampleTest.php file is provided in the tests directory. After installing a new Lumen application, simply run phpunit on the command line to run your tests.

    Lumen automatically configures the cache to the array driver while testing, meaning no cache data will be persisted while testing.

    You are free to create other testing environment configurations as necessary. The testing environment variables may be configured in the phpunit.xml file.

    Defining & Running Tests

    To create a test case, simply create a new test file in the tests directory. The test class should extend TestCase. You may then define test methods as you normally would using PHPUnit. To run your tests, simply execute the phpunit command from your terminal:

    Lumen provides a very fluent API for making HTTP requests to your application and examining the output.

    Testing JSON APIs

    Lumen also provides several helpers for testing JSON APIs and their responses. For example, the get, post, put, patch, and delete methods may be used to issue requests with various HTTP verbs. You may also easily pass data and headers to these methods. To get started, let's write a test to make a POST request to /user and assert that a given array was returned in JSON format:

    1. <?php
    2. class ExampleTest extends TestCase
    3. {
    4. /**
    5. * A basic functional test example.
    6. *
    7. * @return void
    8. */
    9. public function testBasicExample()
    10. {
    11. $this->json('POST', '/user', ['name' => 'Sally'])
    12. ->seeJson([
    13. 'created' => true,
    14. ]);
    15. }
    16. }

    The seeJson method converts the given array into JSON, and then verifies that the JSON fragment occurs anywhere within the entire JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present.

    Verify Exact JSON Match

    If you would like to verify that the given array is an exact match for the JSON returned by the application, you should use the seeJsonEquals method:

    1. <?php
    2. class ExampleTest extends TestCase
    3. {
    4. /**
    5. * A basic functional test example.
    6. *
    7. * @return void
    8. */
    9. public function testBasicExample()
    10. {
    11. $this->post('/user', ['name' => 'Sally'])
    12. ->seeJsonEquals([
    13. 'created' => true,
    14. ]);
    15. }

    The actingAs helper method provides a simple way to authenticate a given user as the current user:

    1. <?php
    2. class ExampleTest extends TestCase
    3. {
    4. public function testApplication()
    5. {
    6. $user = factory('App\User')->create();
    7. $this->actingAs($user)
    8. ->get('/user');
    9. }
    10. }

    Custom HTTP Requests

    1. public function testApplication()
    2. {
    3. $response = $this->call('GET', '/');
    4. $this->assertEquals(200, $response->status());

    If you are making POST, PUT, or PATCH requests you may pass an array of input data with the request. Of course, this data will be available in your routes and controller via the Request instance:

    1. $response = $this->call('POST', '/user', ['name' => 'Taylor']);

    Lumen also provides a variety of helpful tools to make it easier to test your database driven applications. First, you may use the seeInDatabase helper to assert that data exists in the database matching a given set of criteria. For example, if we would like to verify that there is a record in the users table with the email value of [email protected], we can do the following:

    1. public function testDatabase()
    2. {
    3. // Make call to application...
    4. $this->seeInDatabase('users', ['email' => '']);
    5. }

    Of course, the seeInDatabase method and other helpers like it are for convenience. You are free to use any of PHPUnit's built-in assertion methods to supplement your tests.

    Resetting The Database After Each Test

    It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests.

    Using Migrations

    One option is to rollback the database after each test and migrate it before the next test. Lumen provides a simple DatabaseMigrations trait that will automatically handle this for you. Simply use the trait on your test class:

    Using Transactions

    Another option is to wrap every test case in a database transaction. Again, Lumen provides a convenient DatabaseTransactions trait that will automatically handle this:

    1. <?php
    2. use Laravel\Lumen\Testing\DatabaseMigrations;
    3. use Laravel\Lumen\Testing\DatabaseTransactions;
    4. class ExampleTest extends TestCase
    5. {
    6. use DatabaseTransactions;
    7. /**
    8. * A basic functional test example.
    9. *
    10. * @return void
    11. */
    12. public function testBasicExample()
    13. {
    14. $this->get('/foo');
    15. }
    16. }

    When testing, it is common to need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Lumen allows you to define a default set of attributes for each of your using "factories". To get started, take a look at the database/factories/ModelFactory.php file in your application. Out of the box, this file contains one factory definition:

    1. $factory->define('App\User', function ($faker) {
    2. return [
    3. 'name' => $faker->name,
    4. 'email' => $faker->email,
    5. ];
    6. });

    Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the Faker PHP library, which allows you to conveniently generate various kinds of random data for testing.

    Of course, you are free to add your own additional factories to the ModelFactory.php file.

    Multiple Factory Types

    Sometimes you may wish to have multiple factories for the same Eloquent model class. For example, perhaps you would like to have a factory for "Administrator" users in addition to normal users. You may define these factories using the defineAs method:

    1. $factory->defineAs('App\User', 'admin', function ($faker) {
    2. return [
    3. 'name' => $faker->name,
    4. 'email' => $faker->email,
    5. 'admin' => true,
    6. ];
    7. });

    Instead of duplicating all of the attributes from your base user factory, you may use the raw method to retrieve the base attributes. Once you have the attributes, simply supplement them with any additional values you require:

    1. $factory->defineAs('App\User', 'admin', function ($faker) use ($factory) {
    2. $user = $factory->raw('App\User');
    3. return array_merge($user, ['admin' => true]);
    4. });

    Using Factories In Tests

    Once you have defined your factories, you may use them in your tests or database seed files to generate model instances using the global factory function. So, let's take a look at a few examples of creating models. First, we'll use the make method, which creates models but does not save them to the database:

    1. public function testDatabase()
    2. {
    3. // Use model in tests...
    4. }
    1. $user = factory('App\User')->make([
    2. 'name' => 'Abigail',
    3. ]);

    You may also create a Collection of many models or create models of a given type:

    Persisting Factory Models

    The create method not only creates the model instances, but also saves them to the database using Eloquent's save method:

    1. public function testDatabase()
    2. {
    3. // Use model in tests...
    4. }

    Again, you may override attributes on the model by passing an array to the create method:

    1. $user = factory('App\User')->create([
    2. 'name' => 'Abigail',
    3. ]);

    Adding Relations To Models

    You may even persist multiple models to the database. In this example, we'll even attach a relation to the created models. When using the create method to create multiple models, an Eloquent is returned, allowing you to use any of the convenient functions provided by the collection, such as each:

    1. $users = factory('App\User', 3)
    2. ->create()
    3. ->each(function($u) {
    4. $u->posts()->save(factory('App\Post')->make());
    5. });

    Mocking Events

    If you are making heavy use of Lumen's event system, you may wish to silence or mock certain events while testing. For example, if you are testing user registration, you probably do not want all of a UserRegistered event's handlers firing, since these may send "welcome" e-mails, etc.

    Lumen provides a convenient expectsEvents method that verifies the expected events are fired, but prevents any handlers for those events from running:

    1. <?php
    2. class ExampleTest extends TestCase
    3. {
    4. public function testUserRegistration()
    5. {
    6. $this->expectsEvents('App\Events\UserRegistered');
    7. // Test user registration code...
    8. }
    9. }

    If you would like to prevent all event handlers from running, you may use the withoutEvents method:

    1. <?php
    2. class ExampleTest extends TestCase
    3. {
    4. public function testUserRegistration()
    5. {
    6. $this->withoutEvents();
    7. // Test user registration code...
    8. }
    9. }

    Mocking Jobs

    Sometimes, you may wish to simply test that specific jobs are dispatched by your controllers when making requests to your application. This allows you to test your routes / controllers in isolation - set apart from your job's logic. Of course, you can then test the job itself in a separate test class.

    Lumen provides a convenient expectsJobs method that will verify that the expected jobs are dispatched, but the job itself will not be executed:

    1. <?php
    2. class ExampleTest extends TestCase
    3. {
    4. public function testPurchasePodcast()
    5. {
    6. $this->expectsJobs('App\Jobs\PurchasePodcast');
    7. // Test purchase podcast code...
    8. }
    9. }

    When testing, you may often want to mock a call to a Lumen facade. For example, consider the following controller action:

    1. <?php
    2. class FooTest extends TestCase
    3. {
    4. public function testGetIndex()
    5. {
    6. Cache::shouldReceive('get')
    7. ->once()
    8. ->with('key')
    9. ->andReturn('value');
    10. $this->get('/users');
    11. }