Many of the idioms summarized here are worthy of being used as a separate chapter or even a book. You should take this chapter as an introduction to the usage of PHP pattern design, and view some listed reference books for further study.
Test your code
There may be no common code usage that is more important than testing code. A good test can improve the development speed.
In the beginning, this motto may be in conflict with your intuition. You may assert that testing is a free obstacle. In fact, on the contrary, if you fully run those tests to check the public interfaces of your software, you may not change (or worse, damage) the original application software changes the internal execution of the system. Test and verify the accuracy and correctness of your public interfaces, and let yourself change the internal work of some code at will to ensure that your software is correct and there is no bug (error ).
Before discussing more about the benefits of testing, let's take a look at an example. All the test instances in this book use the PHP test framework-SimpleTest. This test frame can be obtained in the http://simpletest.org.
Consider the following code
<? Php
// PHP4
// The subject code
Define ('tax _ rate', 0.07 );
Function calculate_sales_tax ($ amount ){
Round ($ amount * TAX_RATE, 2 );
}
// Include test library
Require_once 'simpletest/unit_tester.php ';
Require_once 'simpletest/reporter. php ';
// The test
Class TestingTestCase extends UnitTestCase {
Function TestingTestCase ($ name = ''){
$ This-> UnitTestCase ($ name );
}
Function TestSalesTax (){
$ This-> assertEqual (7, calculate_sales_tax (100 ));
}
}
// Run the test
$ Test = new TestingTestCase ('testing Unit test ');
$ Test-> run (new HtmlReporter ());
The above code first defines a constant -- TAX_RATE, and a function for calculating the sales tax. Then, the Code contains the essential components for using the SimpleTest framework: the standalone test itself and a "reporter" module used to display the test results.
The TestingTestCase class inherits from the UnitTestCase class of the SimpleTest framework. By extending UnitTestCase, all methods in the TestingTestCase class that start with Test will be considered as Test instances-create conditions to debug your code and assert the results.
TestingTestCase defines a test, TestSalesTax (), which contains an asserted function AssertEqual (). If the first two input parameters are equal, true is returned; otherwise, false is returned. (If you want to display assertEqual () Failure Information, You can input three parameters like this $ this-> assertEqual (7, calculate_sales_tax (100 ), "The sales tax calculation failed ")).
The last two lines of the Code create the entity of the test instance and run it using an HtmlReporter. You can access this web page to run this simple test.
Running this test will display the test name, the details of the failure assertions, and a summary. (Green means success (all assertions pass), while red implies failure (at least one asserted fails ))
Assertion is a common debugging method in software development, which is supported in many development languages. In implementation, assertion is a statement in the program. It checks a boolean expression. A correct program must ensure that the value of this boolean expression is true. If this value is false, if the program is in an incorrect state, the system will give a warning or exit. Generally, assertion is used to ensure the most basic and critical correctness of the program. The assertion check is usually enabled during development and testing. To improve performance, the assertion check is usually disabled after the software is released .)
Note: assertion is a common debugging method in software development. Many development languages support this mechanism. In implementation, assertion is a statement in the program. It checks a boolean expression. A correct program must ensure that the value of this boolean expression is true. If this value is false, if the program is in an incorrect state, the system will give a warning or exit. Generally, assertion is used to ensure the most basic and critical correctness of the program. The assertion check is usually enabled during development and testing. To improve performance, the assertion check is usually disabled after the software is released .)
The above code has an (intentional) error, so the running fails. The result is as follows:
Where is an error in a simple function such as Calculate_sales_tax? You may have noticed that this function does not return results. The following are the correct functions:
Function calculate_sales_tax ($ amount ){
Return round ($ amount * TAX_RATE, 2 );
}
Run the modification and the test is successful.
However, a simple test does not ensure that the Code is stable. For example, if you change calculate_sales_tax () to function calculate_sales_tax ($ amount) {return 7 ;}, the code will pass the test, but it is correct only when 1 dollar is equivalent to 100. You can add additional test methods to test other static values.
Function TestSomeMoreSalesTax (){
$ This-> assertEqual (3.5, calculate_sales_tax (50 ));
}
Or change the TestSalesTax () function to verify the second (and third, and so on) value, as shown below:
Function TestSalesTax (){
$ This-> assertEqual (7, calculate_sales_tax (100 ));
$ This-> assertEqual (3.5, calculate_sales_tax (50 ));
}
So far, there is a better way to add a new test: select the immediate value to test your code. The details are as follows:
Function TestRandomValuesSalesTax (){
$ Amount = rand );
$ This-> assertTrue (defined ('tax _ rate '));
$ Tax = round ($ amount * TAX_RATE * 100)/100;
$ This-> assertEqual ($ tax, calculate_sales_tax ($ amount ));
}
TestRandomValuesSalesTax () introduces the method assertTrue (). If the first input variable is equal to boolean, assertTrue () passes. (Like method assertEqual (), method assertTrue () returns a failed message after receiving an optional and additional one ). Therefore, TestRandomValuesSalesTax () first considers that the constant TAX_RATE has been defined, and then uses this constant to calculate the tax revenue of the randomly selected quantity.
However, TestRandomValuesSalesTax () also has a problem: it relies heavily on the calculate_sales_tax () method (). Testing should be unrelated to special implementation details. A better test should only establish a reasonable demarcation line. The following test assumes that the sales tax will never exceed 20%.
Function TestRandomValuesSalesTax (){
$ Amount = rand );
$ This-> assertTrue (calculate_sales_tax ($ amount) <$ amount * 0.20 );
}
Ensuring that your code works properly is the primary purpose of the test, but when testing your code, you should realize that there are some additional and secondary purposes:
- Testing allows you to write code that is easy to test. This makes the code loose coupling, complex design, and good controllability.
- Testing allows you to clearly understand the expected results of Running code and focus on module design and analysis from the very beginning. Passing the test will also allow you to consider all possible input and corresponding output results.
- The purpose of the test is to quickly understand the encoding. In other words, test cases act as "instances" and "documents", and accurately demonstrate how to build a class, method, and so on. In this book, I sometimes use a test example to demonstrate the expected functions of the Code. By reading the declaration of a test method, you can clearly understand how the code runs. A test instance defines the running status of the Code in explicit usage.
Finally, if your test set-the set of test instances-is thorough, and when all tests pass, you can say that your code is complete. Interestingly, this idea also happens to be one of the features of Test Driven Development.
Test Driven Development (TDD) is also considered as Test First Coding (pre-encoding Test ). Test First Coding is a way to make the Test more advanced: Write the Test before you write any code. You can use Test Driven Development: By Example from the author Beck (examples in this book are developed in JAVA, but the code is quite readable, and the introduction and description of the topic are well done ).
Note:Agile Development)
Recently, standalone testing, especially surveying-driven development, has been closely linked with agile development methodologies, such as extreme programming (XP ). Extreme Programming focuses on the rapid and repeated development of functional code to the customer, and the change of customer needs as a necessary part of the development process. The following are some online resources for learning Agile programming:
Functional Testing
Most of the test examples in this book are used to test the code for objects, but all forms of programming can be learned from them. Standalone testing frameworks, such as PHPUnits and SimpleTest, can also be easily used to test functional functions. For example, in the SimpleTest example above, it is used to test the calculate_sales_tax () function. Programmers all over the world: Put single test cases in your function library!
I hope that after the above discussion, you will also be promoted-Test Infected )! (This term, originally written in Erich Gamma, can be found in the article http://junit.sourceforge.net/doc/testinfected/testing.htm for details), as Gamma writes, you may feel tedious at the beginning, but when you build a broad test set for your program, you will be more confident in your code!