Test
Brief introduction
Testing is the core concept of Laravel construction. In fact, Laravel supports PHPUnit testing out of the box, and your app's root directory contains phpunit.xml files. At the same time, Laravel also comes with some handy help methods that can make you plump for application testing.
A exampletest.php file is available in the tests directory. After the installation completes the Laravel app, you only need to run the PHPUnit command in the root directory to perform the test.
Test environment
When you run the test, Laravel automatically sets the configuration environment to testing. At the same time, Laravel automatically configures the session and cache to be an array driver. This means that the session or cached data is not persisted during the test.
If you want, you can create a test environment yourself. The testing environment variable is configured in the Phpunit.xml file, but you want to make sure that you run the Config:clear Artisan command to clear the configuration cache before running the test.
Define & Run Tests
You can use the Make:test Artisan command to create a test case:
PHP Artisan make:test usertest
This command creates a new Usertest class in the tests directory. You can then define some test methods in the class as you would with PHPUnit. Then you just need to execute the phpunit command at the terminal to run the test:
Assettrue (True);} }
Note: If you define your own SetUp method in a test case, you need to make sure that the Parent::setup method is called first.
Application Testing
Laravel provides a very smooth API to build HTTP request check output or even fill tables. For example, let's look at the exampletest.php file under the tests directory:
Visit ('/') ->see (' Laravel 5 ') ->dontsee (' Rails ');} }
The Visit method can construct a GET request in the application. The See method asserts that the given text should be seen from the application's response. The Dontsee method is just the opposite of see, which asserts that we should not be seeing the given text. This is the most basic application test provided by Laravel.
Interacting with an app
Of course, you can do more than this simple assertion in response to a given text. Let's take a look at some examples of clicking links and populating the form:
Click on the Super Chain
In this test, we construct a request for the application that returns a clickable hyperlink in the response, and we assert that it should be directed to the given URL. For example, let's assume that the application returns a hyperlink with the text "About Us":
About Us
Now, let's write a test and assert that the click Link jumps to the appropriate page:
Public Function Testbasicexample () { $this->visit ('/') ->click (' About Us ') ->seepageis ('/ About-us ')}
Interacting with Forms
Laravel also offers a variety of ways to test forms. The Type,select,check,attach, and the press method allow you to interact with all form inputs. For example, let's imagine a form that exists on the registration page:
We can write a test to complete the form and check the results:
Public Function testnewuserregistration () { $this->visit ('/register ') ->type (' Taylor ', ' name ') - >check (' terms ') ->press (' Register ') ->seepageis ('/dashboard ');}
Of course, if your form contains other inputs such as radio buttons or drop-down boxes, you can also easily populate these types of fields. Here is a list of all the form action methods:
Method |
Description |
$this->type ($text, $elementName) |
Enter for a given field |
$this->select ($value, $elementName) |
Select a radio button or drop-down box |
$this->check ($elementName) |
Select the check box |
$this->uncheck ($elementName) |
Uncheck check box |
$this->attach ($pathToFile, $elementName) |
Attach a file to the form |
$this->press ($buttonTextOrElementName) |
Click the button for the given text or name |
Interacting with Attachments
If your form contains the file input type, you can use the Attach method to attach the attachment:
Public Function testphotocanbeuploaded () { $this->visit ('/upload ') ->type (' File Name ', ' name ') - >attach ($absolutePathToFile, ' photo ') ->press (' Upload ') ->see (' Upload successful! ');}
Testing JSON APIs
Laravel also provides a number of helpful methods for testing JSON APIs and their responses. For example, Get,post,put,patch, and the Delete method can be used to publish a request for a corresponding HTTP behavior. You can easily pass data and header information into these methods. Before we begin, let's write a test of a POST request to assert that/USER returns the JSON format of the given array:
JSON (' POST ', '/user ', [' name ' = ' Sally ']) ->seejson ([ ' Created ' = True, ]);} }
The Seejson method converts the given array to JSON, and verifies that the corresponding fragment appears in the full JSON of the application response. So, if there are other JSON attributes in the response, the test will still be passed.
Verifying exactly-matched JSON
If you want to validate the full JSON response, you can use the Seejsonequals method unless the JSON corresponds exactly to the given array, otherwise the test will not be passed:
JSON (' POST ', '/user ', [' name ' = ' Sally ']) ->seejsonequals ([ ' Created ' = True, ]);} }
Validate Matching JSON structure
It is also possible to verify that the JSON response takes a given structure. You can use the Seejsonstructure method and pass a nested list of keys:
Get ('/USER/1 ') ->seejsonstructure ([ ' name ', ' pet ' = = [ ' name ', ' age ' ] );} }
In the example above, it is shown that you expect to get a JSON with the name and pet properties, and the pet key is an object that contains the name and age attributes. If additional keys are included, the Seejsonstructure method does not fail. For example, if pet also contains the weight attribute, then the test will still be passed.
You can use * to assert that each item in the returned JSON structure should contain the listed attributes:
Get ('/users ') ->seejsonstructure ([' * ' = ' = ' id ', ' name ', ' email ' ] );} }
You can also nest using *, in the following example, we assert that each user returned by the JSON response should contain the listed properties, and that the pet attribute should also contain the property given:
$this->get ('/users ') ->seejsonstructure ([' * '] = [' id ', ' name ', ' email ', ' pets ' = [ ' * ' = ' [ ' name ', ' age ']]] ;
Session/Authentication
Laravel provides a variety of help methods for sessions during testing. First, you need to set the session data by the Withsession method based on the given array, which is usually used to set some session data before the request to the test application is preceded by:
Withsession ([' foo ' = ' Bar ']) ->visit ('/');} }
Of course, the common use of sessions is to retain the user's state, such as user authentication. The Actingas Help method provides a way to use a given user as the current authenticated user. For example, we can use a model factory to generate an authenticated user:
Create (); $this->actingas ($user) ->withsession ([' foo ' = ' Bar ']) ->visit ('/') ->see (' Hello '). $ User->name);} }
You can also pass a given guard name to the second parameter of the Actingas method to select the user-certified guard:
$this->actingas ($user, ' backend ')
disabling middleware
When testing the application, you can easily ban the middleware in the test. This allows you to isolate test routes and controllers without the worry of middleware. You can simply introduce withoutmiddleware trait to disable all middleware in the test class:
If you want to disable middleware only in individual test methods, you can use the Withoutmiddleware method in the method:
Withoutmiddleware (); $this->visit ('/') ->see (' Laravel 5 ');} }
customizing HTTP Requests
If you want to construct a custom HTTP request and return the full Illuminate\http\response object, you can use the call method:
Public Function TestApplication () { $response = $this->call (' GET ', '/'); $this->assertequals (->status, $response ());}
If you construct a post,put, or PATCH request, you can pass an array as the input data for the request. Of course, this data can be used in your routing and controller through the Request instance:
$response = $this->call (' POST ', '/user ', [' name ' = ' Taylor ']);
PHPUnit Assertion
Laravel provides a number of additional assertion methods for the PHPUnit test:
Method |
Description |
->assertresponseok (); |
Asserts that the client response returns an OK status code |
->assertresponsestatus ($code) |
Assert that the client responds to a given status code |
->assertviewhas ($key, $value = null); |
Asserts whether the view of the response contains a given piece of data. |
->assertviewhasall (array $bindings); |
Asserts whether the view contains all the bound data |
->assertviewmissing ($key); |
Asserts whether the given fragment is missing from the view |
->assertredirectedto ($uri, $with = []); |
Asserts whether the client is redirected to the given URI |
->assertredirectedtoroute ($name, $parameters = [], $with = []); |
Asserts whether the client is redirected to a given action |
->assertsessionhas ($key, $value = null); |
Asserts whether a given key is included in the session |
->assertsessionhasall (array $bindings); |
Asserts whether the session contains data for a given list |
->assertsessionhaserrors ($bindings = [], $format = null); |
Assert whether the session contains incorrect data |
->asserthasoldinput (); |
Asserts whether the session contains old input |
->assertsessionmissing ($key); |
Asserts whether a given key is missing from the session |
Collaborating with databases
Laravel also provides a variety of useful tools to make it easier to test database-driven applications. First, you can use the Seeindatabase method to assert whether a given specification can match the corresponding data in the database. For example, if you want to verify that the Users table contains a record of email as sally@example.com, you can do this:
Public Function Testdatabase () {//* call to Application ... $this->seeindatabase (' users ', [' email ' = ' sally@example.com ']);
Of course, methods such as Seeindatabase are just for the convenience of testing. You are free to use any of the PHPUnit's own assertion methods to complement your test.
Resetting the database after each test
We typically restore the database after each test so that the previous test data does not interfere with subsequent tests.
Using migration
One option is to perform database rollback and migration operations before the next test. Laravel provides a concise databasemigrations trait to handle these, you only need to introduce this trait in the test class:
Visit ('/') ->see (' Laravel 5 ');} }
Using transactions
Another option is to wrap the transaction of the database in each test case, and this time, Laravel provides a convenient databasetransactions trait to handle these:
Visit ('/') ->see (' Laravel 5 ');} }
Note: This trait only wraps transactions for the default database connection.
Model Factory
When testing, it is often necessary to add some data records in the database that are required for testing before executing the test. Laravel allows you to use "factories" to define some default property settings for your eloquent model in place of these manual add data behaviors. Before we get started, let's take a look at the app's database/factories/modelfactory.php file. The file contains only the definition of a factory:
$factory->define (App\user::class, function (Faker\generator $faker) { return [ ' name ' = = $faker Name, ' email ' = $faker->email, ' password ' and ' Bcrypt ' (str_random), ' remember_token ' = Str_random (Ten), ];});
In closures in the factory definition, you can return the default values that are used as tests in some models. This closure will receive an instance of the Faker PHP class library, which will help you generate some random data for testing.
Of course, you are free to add additional factories to the modelfactory.php file. You can also create additional factory files for effective organization management. For example, you can create a userfactory.php and a commentfactory.php file under the Database/factories directory.
Multiple plant types
Sometimes, you might want to have multiple factory types on the same eloquent model. For example, you might want to have an administrator's factory in addition to ordinary users. You can use the Defineas method to define these factories:
$factory->defineas (app\user::class, ' admin ', function ($faker) { return [ ' name '] = $faker->name, ' email ' = $faker->email, ' password ' and Str_random (Ten), ' Remember_token ' and Str_random (10 ), ' admin ' = = true, ];});
You can use the raw method to retrieve the properties of the underlying factory, which can be used for the reuse of properties, and then merge to add the extra properties you need:
$factory->defineas (app\user::class, ' admin ', function ($faker) use ($factory) { $user = $factory->raw (app\ User::class); Return Array_merge ($user, [' admin ' = true]); });
Using the factory in the test
Once you have defined the factory, you can use the Global helper function Factory factory method to generate an instance of the model in your test file or database seed file. So, let's look at some examples of creating models. First, we'll use the Make method, which will create some models but not save them to the database:
Public Function Testdatabase () { $user = Factory (App\user::class)->make (); Use model in tests ...}
You can override the default values in the model by passing an array into the Make method. Only the specified part will be replaced, while the rest will be left as the factory defined default value:
$user = Factory (App\user::class)->make ([ ' name ' = ' Abigail ',]);
You can also create collections of multiple models based on a given type:
Create three App\user instances ... $user = Factory (App\user::class, 3)->make ();//Create an App\user "admin" instance ... $user = Factory (app\user::class, ' admin ')->make ();//Create three App\user "admin" instance ... $user = Factory (app\ User::class, ' admin ', 3)->make ();
Plant Model Persistence
The Create method not only creates a model instance, it also stores it in the database using the eloquent Save method:
Public Function Testdatabase () { $user = Factory (App\user::class)->create (); Use model in tests ...}
This time, you can also pass an array into the Create method to override the default property values:
$user = Factory (App\user::class)->create ([ ' name ' = ' Abigail ',]);
To add a relationship to a model
You can even persist multiple models into the database. In this example, we will even attach an association model to the model we created. When creating multiple models using the Create method, a collection instance is returned, which allows you to use the methods of the collection instance, such as each:
$users = Factory (App\user::class, 3) ->create () ->each (function ($u) { $u->posts ()->save ( Factory (App\post::class)->make ()); });
Correlation & Attribute Closures
You can also use a closure within a factory definition to attach a relational model, for example, if you want to create a Post with an associated User instance, you can do this:
$factory->fefine (App\post::class, function ($faker) { return [ ' title '] = $faker->title, ' Content ' = $faker->paragraph, ' user_id ' = function () { return factory (App\user::class)->create ()->id; } ];});
These closures also receive an array of evaluation attributes that the factory contains:
$factory->define (App\post::class, function ($faker) { return [ ' title '] = $faker->title, ' Content ' = $faker->paragraph, ' user_id ' = function () { return factory (App\user::class)->create ()->id; }, ' user_type ' = function (array $post) { return app\user::find ($post [' user_id ']) type; } ]; });
Simulation
Simulation Events
If you use the event system extensively in Laravel, you may want to test without triggering an event or simulating running some events. For example, if you test the user registration, you may not want to trigger all userregistered events, as these may send e-mails and so on.
Laravel provides a convenient expectsevents method to verify that the expected events are triggered, but avoids the actual execution of these events:
Expectsevents (app\events\userregistered::class); Test user Registration ... }}
You can also use the Doesntexpectevents method to verify that a given event has not been triggered:
Expectsevents (app\events\podcastwaspurchased::class); $this->doesntexpectevents (app\events\paymentwasdeclined::class); Test Purchasing Podcast ... }}
If you need to avoid all event triggers, you can use the Withoutevents method:
Withoutevents (); Test User Registration Code ... }}
Simulation tasks
Sometimes you want to test the controller for distribution of assigned tasks in a simple way when building the request to the application. This allows you to isolate test your routing/controller and your task logic, and of course, you can write a test case again to separate the execution of the test task.
Laravel provides a convenient Expectsjobs method to verify that the desired task is being distributed, but the task is not actually distributed for execution:
Expectsjobs (app\jobs\purchasepodcast::class); Test Purchase Podcast code ... }}
Note: This method is only used to test the distribution of dispatchesjobs trait or dispatch help methods. It does not detect direct use of the Queue::p Ush published tasks.
Mock masks
When testing, you may often need to simulate the invocation of a Laravel mask. For example, consider the following controller operation:
!--? phpnamespace app\http\controllers;use Cache;class Usercontroller extends controller{/** * Show A list of all users of the application * * @return Response */Public Function index () {$value = Cache::get (' key '); }} We can use the Shouldreceive method to impersonate the call to the Cache mask, which returns a mock instance of the mockery. Since masks are actually parsed and managed through Laravel service containers, they are more measurable than the general static classes. For example, let's simulate the call to the Cache mask:
!--? phpclass Footest extends testcase{public function t Estgetindex () {cache::shouldreceive (' get ')--->once ()->with (' key ')->andre Turn (' value '); $this->visit ('/users ')->see (' value '); }}
Note: You should not impersonate the Request mask. You should use HTTP helper methods such as Call and post to pass the input you want when you run your tests.