Rapid development of PHP applications using the CodeIgniter framework (8)

Source: Internet
Author: User
Tags floor function php error php error reporting
This chapter describes how CI helps you test the code. Testing is the heart of an application. We use it to test other remote applications. we also want to test ourselves because it is also code. CI makes testing easy. Use CI test code

This chapter describes how CI helps you test the code. Testing is the heart of an application. We use it to test other remote applications. we also want to test ourselves because it is also code. CI makes testing easy.

However, 'test' has a wide range of meanings, so let's start with the difference between the two main test types and analyze how you should perform the test.

Let's take a look at how the CI class helps you test the code:

. Unit test

. Benchmark Test

. Profiler

. CI helps you test the database when there is no production data

Why test, for whom?

There are a lot of literature about the test. It has become an industry. Complex programs require a unit of testers to test the software. In addition, the concept of 'test-driven developing' is that you first design your test program before writing your first line of code, and then hand over the code you have written to them.

On the other hand, many programmers do not perform any system tests. Because testing seems too difficult, annoying, and takes a lot of time. Maybe we will perform a few tests and hope the rest will work properly.

CI provides some methods to make testing easier. Or you can say-more fun.

There are two main test types:

. Unit test: adopt the 'bottom-up 'method. They view a code block, such as a function, and put some variables to see if they return correct results.

. Complete test: these are from top to bottom '. They focus on something to see if the system can do it. For example, they try to log on to your website (using a valid user name and password) to see if the system works properly. (Once they tried to log on with a wrong password ...)

As you can see, it is a different philosophy. Unit tests do not know or care about the results. complete tests care about the results and do not know whether the code works correctly.

The important thing is to consider why you want to test. What worries you the most? What are the most likely problems that make you embarrassed? What information do you want to obtain from your test? Is it just good or bad, or more details? How long can you write and test code for each application?

We are developing our testing website, but when programming, we need to test our code. Of course, we try to anticipate everything the user will do and every possible situation. Unit testing is useful in many ways: design testing methods help you improve code design.

Once our code is uploaded to a production server, the size of its data increases Daily beyond our control. The worst thing is that the customer finds an error message or a blank screen, and expects you to solve the problem while busy with other things. This is why we are creating this website and testing other remote websites.

CI can help us check the website to see if the following is happening:

First, we have expected many possible problems. For example, I may use the ID to perform a database query and delete a record. Yes, it can work: I actually perform this operation and test it. But what happened: If-somehow-the code is calling a non-existent table? Or is there a problem with the ID number? Or is there no ID value at all? This is helpful for unit testing.

Second, when I write more code elsewhere, does my first part of code work as required, or have I accidentally modified the part on which the first part of the code depends? Again, a test is given to the unit. They can also regularly help us check the product server (including all its components, for example, if the database is on a separate server, there is no need to do a normal 'ping' check !)

CI helps you a lot, no matter what situation you are in. It does not provide a function Test class, but you can use other PHP code for this test. But let's take a look at how CI captures errors in your code.

CI error operations

CI has its own system for detecting and reporting errors. On the one hand, these are the simplest and most common tests: they are helpful (or irritating) information: When you are writing code and it does not work properly, you will see this information.

By default, CI displays all errors on the screen. The other option is "no error". if you do not display the error information, you cannot handle the error. Therefore, it is necessary to debug the error. All actions are controlled by the index. php file. The style is as follows:
/*
| ---------------------------------------------------------------
| PHP ERROR REPORTING LEVEL
| ---------------------------------------------------------------
|
| By default CI runs with error reporting set to ALL. For security
| Reasons you are encouraged to change this when your site goes live.
| For more info visit: http://www.php.net/error_reporting
|
*/
Error_reporting (E_ALL );

This is a PHP command that reports all errors. To disable the error report, change the last line:

Error_reporting (0 );

This method is suitable for use on product websites. it can suppress all error messages.

CI has three functions: show_error (), show_404 (), and log_message (). it controls how errors are displayed on your system. (Normally, these functions are global: you can use them without loading. just use them !). In fact, show_error () and show_404 () are usually generated by default; the previous one shows your error in a neat small HTML box at the top of the screen; the next page displays a '123' page when you attempt to request a webpage that does not exist.

The third function, log_message (), is more interesting. You may want to develop your own error logs for a variety of reasons, one of which may be because you cannot access the log files on your ISP's Apache. First, you need to set the permission to ensure that the/system/logs directory is readable and writable. Then you set the logging level in the config file:
/*
| --------------------------------------------------------------------------
| Error Logging Threshold
| ------------------------------------------------------------------------
|
| If you have enabled error logging, you can set an error threshold
| Determine what gets logged. Threshold options are:
|
| 0 = Disables logging
| 0 = Error logging TURNED OFF
| 1 = Error Messages (including PHP errors)
| 2 = Debug Messages
| 3 = Informational Messages
| 4 = All Messages
|
| For a live site you'll usually only enable Errors (1) to be logged
| Otherwise your log files will fill up very fast.
|
*/
$ Config ['log _ threshold '] = 4;
/*

Log is enabled.

If you modify index. php to disable the error message display, the error log will not work. Therefore, you can see the information, but your users cannot.

When you enable logging, CI generates a new record file every day and writes information to this file. But be careful, these record files can quickly become very large.

In actual use, you may need to develop error handling code that displays specific error information when something occurs.

CI unit test class

Now let's get started with some appropriate testing work: checking whether your code can work in different environments.

CI makes the unit test class as simple as other classes. You load it here:

$ This-> load-> library ('unit _ test ');

Then, prepare three variable numbers for each test:

. $ Test-actual test content, usually a PHP expression

. $ Expected_result-the expected result

. $ Test_name-name of the test you want to display

The two tests for the PHP function floor () are listed below. (Floor () is the integer function of PHP.) the first expected result is correct, and the second is incorrect. (A deliberate error ):

$ Test = floor (1.56 );
$ Expected_result = 1;
$ Test_name = 'tests php floor function ';
$ This-> unit-> run ($ test, $ expected_result, $ test_name );
$ Test = floor (2.56 );
$ Expected_result = 1;
$ Test_name = 'tests php floor function ';
$ This-> unit-> run ($ test, $ expected_result, $ test_name );


Added:

Echo $ this-> unit-> report ();

The displayed result is formatted HTML:

Test Name tests php floor function
Test Datatype Float
Expected Datatype Integer
Result Passed
File Name E: \ xampplite \ htdocs \ packt2 \ system \ application \\
Controllers \ tests. php
Line Number 108
---------------------------------------------------------------
Test Name tests php floor function
Test Datatype Float
Expected Datatype Integer
Result Failed
File Name E: \ xampplite \ htdocs \ packt2 \ system \ application \\
Controllers \ tests. php
Line Number 113

If you want to analyze the system or save it, use:

Echo $ this-> unit-> result ();

Returns a two-dimensional array that you can use:

Array (
[0] => Array
([Test Name] => tests php floor function
[Test Datatype] => Float
[Expected Datatype] => Integer
[Result] => Passed
[File Name] => E: \ myfile. php [Line Number] => 69)
[1] => Array
([Test Name] => tests php floor function
[Test Datatype] => Float
[Expected Datatype] => Integer
[Result] => Failed
[File Name] => E: \ myfile. php
[Line Number] => 73)
)


So now we have a simple way to get the test results.

Except for a simple test like this (floor (1.56) is equal to 1 ?) CI unit test classes also test data types (is_string, is_bool, is_true, and so on. -Complete list in the user manual:

You can put the following expression:

$ Expected_result = 1;

Replace:

$ Expected_result = 'is _ float ';

The test process is the same as the previous one.

If you put such a test code everywhere in your password, it may run very slowly and show all the diagnostics on your screen. But you can stop it. Simply add the following code to your constructor:

$ This-> unit-> active (FALSE );

And (surprisingly) if you change FALSE to TRUE, the information will be displayed again, and you can even do so dynamically.

When to use unit test

In fact, few people will test a PHP built-in function. However, it is valuable to test your own functions. To check whether they can return correct results, you need to worry about the following:

. Are they doing well?

. But the user will immediately think that in a different environment, can it still work normally?

. Or you will write more code or modify the existing code, so that your function cannot work normally.

Sometimes errors are caused by programming problems, so we can use programming to capture and modify errors. You can have fun testing with different parameters.

Let's go back to the example where we run a database query to delete records with the specified ID value. What will it do if:

. Is id null, or is no value given? (It is particularly important that you may accidentally delete all the data in the table .)

. Is ID not an integer? ("X", for example ?)

. The ID card is an integer but out of the range (you have 1000 records in your table, but the ID is 1001 ?)

. Is ID a negative integer?


It is interesting to come up with different test conditions.

Put these parameters into the function in unit test and check the result. Of course, the results can be imagined. An error is reported in the first and second cases. You should modify it to prevent it from happening. Therefore, the unit test fails after execution.

We define the results we want to get from each test. if the results are the same as what we set, the test will pass. However, if the program throws an exception during the test and the subsequent code is no longer executed, how can we complete the unit test? This requires that we first ensure that the program has no syntax errors, so that the function can execute all the code. After all, unit tests are not used to deal with syntax errors. this is the work of the PHP environment.

The third case of the above assumption is that the ID is out of range, which is not a code error. the database can safely handle this situation. However, you can perform some inspection before sending the query to the database. Or you can run it, because it may cause the database to return an error message, so you need to replace the information provided by the system with your own error message, such as "sorry, the system is busy and cannot provide services ".

Unit test example


Let's write some code to test this 'delete' function. I have created a 'delete' function (put in a model) so that we can test it. if the unit test fails, $ dbvalue is returned.

If ($ test = 'yes ')
{
$ Place = _ file).20.line __;
$ Dbvalue = "exception at $ place: sent state value $ state
Trydelete function ";
Return $ dbvalue;
}

If the test is successful, a simple loop returns 'OK' in $ dbvalue. the test code is very simple. First, we create an array of ID values and the expected results. In other words, if we try to delete an ID card with an ID value of ''or 'ABC', the system should throw an exception. if the ID is 1, or 9999, the system should accept it as a valid ID and it will return 'OK '.

Therefore, the key name of the array is the test condition you have given, and the value is the result you expect the function to return.

$ Numbers = array (
''=> 'Exception ',
'Null' => 'exception ',
'X' => 'exception ',
'20140901' => 'OK ',
'-1' => 'exception ',
'1' => 'OK'
);

Now, use the following code to cyclically pass each element of the $ numbers array to the single-class without height of CI for all tests.

The test will run the $ this-> delete () function to record the records and ID values ($ testkey) in the 'Fred 'table you want to delete ).

Foreach ($ numbers AS $ testkey => $ testvalue ){
$ Dbvalue = $ this-> delete ('Fred ', $ testkey );
$ Result. = $ this-> unit-> run (preg_match ("/$ testvalue /",
$ Dbvalue), 1, $ dbvalue );
}


Remember, the CI unit test gives you three arguments:

. $ Test: for each array key, we call $ testkey as a parameter to delete the function. the array key is the ID value given. The function returns a value. ($ Dbvalue ). Our $ test will use regex to compare the value. we expect it to be $ testvalue, which is the value corresponding to the key in the array. (It includes 'OK' or 'exception '?)

. $ Expectedresult is '1', because if our code is correct, we expect regex to find a match. We want 'null' to return an "exception" and '1' to return "OK ".

. $ Testname: this parameter is optional: it is the string returned by the test and is used to explain what tests we perform and what parameters we use.

You can see from the results that all tests return 'passed ', so we can have confidence in our code. (The data types of test results and expected results are all integers, even if our input may not be an integer, because the test is actually a comparison of a regular expression, return 1 or 0 ).


It is fun and actually useful. the test results are stored in an array.

For example, if ID is a number, and if it is not an integer, the following test is used:

'3. 5' => 'exception ',

What is the result?

The results will surprise you (I am also): This test does not get the expected results, it shows that your function will regard 3.5 as a function. The reason is that PHP performs a loose 'Equality 'test. if you want to get the correct result in this case, you need to set the comparison to the 'stern' mode. To set this mode, use:

$ This-> unit-> use_strict (true );

CI benchmark test class

This class allows you to test the time required to run from one point to another. Insert a line of code at the start of the test:

$ This-> benchmark-> mark ('where ');

Insert in another line of code:

$ This-> benchmark-> mark ('there ');

Then you insert the third line to tell you the execution time:

$ Fred = $ this-> benchmark-> elapsed_time ('where', 'there ');

Then you can print the result, $ fred, or do anything you want to do.

Benchmark tests can use any name you like, as long as they are different and you can set many groups. You can use these tests to see if your code execution takes too much time to complete. If your page is loaded for too long, you can insert some benchmark test identifiers to test the code block that causes latency.

We are not too interested in the test of our website monitoring application. When we log on to our website on the English site, we hope their speed is acceptable. It doesn't make much sense to have a short execution time each time. However, if we test the same tracing basis point consecutively, we may notice that it will change: this will provide us with clues to the cause of the problem. A database query may take a lot of time; it may be that our host is not in a stable state. To achieve our goal, we will collect $ fred's content and store it in the database.

CI Profiler class

The profiler class is wonderful. you insert a line of code in a function of your class (it works in the constructor, so it makes sense to put it there.) this line of code is:

$ This-> output-> enable_profiler (true );

If you change your mind, you can modify it:

$ This-> output-> enable_profiler (false );

Insert this line of code to get a complete report on your screen. Display the time spent by the CI super object and your controller, as well as the time spent by the $ _ POST array and database query. This is particularly useful in the development phase.

If you add your own benchmark, it will also display these. You must use a special name to name your benchmark-they must be included in "_ start" and "_ end". the names of each group must be different:

$ This-> benchmark-> mark ('Fred _ start ');

In addition, there are:

$ This-> benchmark-> mark ('Fred _ end ');


As you can see, the interval between the two datum points is expressed as 'Fred '.

Test with simulated database data

Dynamic websites work around databases. If you are testing them, you should test whether your code can actually modify a database. End-to-end test: for example, if your test shows whether you can log on with the correct username/password combination, you may need to read a database and perform this operation.

But it is dangerous to test whether you can update, insert, or delete data in a production database, because it will damage your real data!

Remember: CI allows you to declare more than one database, and it is easy to switch between them? -See chapter 2. With this function, you can easily create a simulated database, add, change, and delete data in it.

You can also use CI to create and delete tables, or create and delete databases based on your host and permissions. CI:

$ This-> db-> query ('your query here ');

The function allows you to run any SQL query, including something like this:

$ This-> db-> query ('create table fred (id INT, name VARCHAR (12), INDEX (id ))');

You can create a new table, or:

$ This-> db-> query ("insert into fred values (1, 'Smith ')");

Insert a row of data to the fred table.

Therefore, through several lines of code, CI allows you to establish a simulated data for a complete test and delete the simulated database when you do not need it. You may perform unit tests on the delete () function several times to see if the function works normally when there are different ID values.

Now you are going beyond simple unit tests. If we perform a unit test to delete data in our table, we need to check whether the data is actually deleted. This is easy to implement with the following code, and then use the CI unit Test class. And its AR class:

$ Test = $ this-> db-> count_all ('Fred ');
$ Expected_result = 0;
$ Test_name = 'tests number of entries left in table after unique
Entry


$ This-> unit-> run ($ test, $ expected_result, $ test_name );

$ This-> db-> count_all: all the results in the calculation table, and we know that there should be no results now. You can easily use this code to check the 'insert' operation to see if there is a record stored in the table after the operation.

Because this is virtual data, we generate it specially for testing, and we fully know what to expect, and it doesn't matter what to do. Remember to restore the system to the product database after the test. Otherwise, you will get a strange result.

Control and schedule

Testing is the heart of an application, so it is important not to test, but to make the test effective.

You should remember that in Chapter 4th, we have an SQL file for table creation, with a table named tests and another table named events. each time the website performs a test run, it looks for two fields in the tests table: frequency and last_done. if the value in frequency is "hourly", we will check "last_done. If no test is performed in this hour, we will start the test, then update its last_done field to the time of this test.

After the test is completed, the program inserts a record in the events table, where the tested website ID and various other test result information are inserted. This table provides statistics on our website and our customer website, pick out individual tests, or all tests for a given website, and so on.

The benchmark class we discussed earlier in this chapter is not involved at all: when you test a function as mentioned above, it is a good idea to put the benchmark into the timing. you can get the data on how much time the test takes. Save the time to the events table, where there is a field timetaken, which is the number of seconds it takes to put a floating point type into the test. If you regularly evaluate tests, you may draw many conclusions. for example, if the duration is long, it may be that the ISP is overloaded, or your webpage has too much content, or your website becomes very famous, and traffic increases greatly. you need to increase your bandwidth.

In either case, frequent tests will enable you to detect accidents and troubleshoot them as soon as possible.

Summary

We have spent a lot of time in testing. It is not the most exciting content, but if you are developing a website, testing is a good way to ensure you have a good night's sleep.

We have seen how CI handles errors and displays error information, but when your website officially starts running, you can close them (or stop log operations ).

We learned how to operate CI unit test tools. We also read benchmark, which can calculate the running time between any code block.

Profiler is a great tool for displaying a lot of information when you write code. CI provides a series of good tools for developing and testing your code.

We also learned how to use a simulated database to debug some code for database interaction. it will not damage your production database.

We can also integrate some external code for CI, so that we can create web robots to test the complete functions of remote websites.


Use CI for communication programming
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.