»¶ÓÄú·ÃÎÊÎÒ°®IT¼¼ÊõÍø£¬½ñÌìС±àΪÄã·ÖÏíµÄ±à³Ì¼¼ÊõÊÇ£º¡¾¡¶PHPÉè¼ÆÄ£Ê½½éÉÜ¡·µÚÁùÕ α¶ÔÏóģʽ¡¿£¬ÏÂÃæÊÇÏêϸµÄ·ÖÏí£¡
¡¶PHPÉè¼ÆÄ£Ê½½éÉÜ¡·µÚÁùÕ α¶ÔÏóģʽ
ÃæÏò¶ÔÏóµÄ±à³ÌÖ®ËùÒԷḻ¶à²Ê£¬²¿·ÖÊÇÓÉÓÚ¶ÔÏó¼äµÄÏ໥ÁªÏµÓë×÷Óá£Ò»¸öµ¥Ò»µÄ¶ÔÏó¾ÍÄÜ·â×°Ò»¸ö¸´ÔÓµÄ×Óϵͳ£¬Ê¹ÄÇЩºÜ¸´ÔӵIJÙ×÷Äܹ»Í¨¹ýһЩ·½·¨µÄµ÷Óöø¼ò»¯¡££¨ÎÞËù²»ÔÚµÄÊý¾Ý¿âÁ¬½Ó¾ÍÊÇÕâÑùµÄÒ»¸ö¶ÔÏóʵÀý¡££©
È»¶ø¾³£ÓÐÕâÑùµÄÇé¿ö£¬¶ÔÏó¼äµÄ½»»¥ÐÔÊÇÈç´Ë¸´ÔÓÒÔÖÁÓÚÎÒÃDz»µÃ²»Ãæ¶ÔÀàËÆ“ÏÈÓ즻¹ÊÇÏÈÓе°”ÕâÑùÉËÄÔ½îµÄÎÊÌ⣺ÈçºÎ´´½¨²¢²âÊÔÕâÑùÒ»¸ö¶ÔÏó£¬ËûҪôÒÀÀµÓںܶàÒÑ´´½¨µÄ¶ÔÏó£¬ÒªÃ´ÒÀÀµÓÚÆäËûһЩÄÑÒÔÒâʶµ½µÄÇé¿ö£¬ÈçÕû¸öÊý¾Ý¿âµÄ´´½¨ºÍ²âÊÔ¡£
ÎÊÌâ
ÈçºÎ·Ö¸ô²¢²âÊÔÒ»¸öÓëÆäËû¶ÔÏóºÍ×ÊÔ´ÓйصĴúÂë¶Î£¿ÓÖÈçºÎÔÙ´´½¨Ò»¸ö»ò¶à¸ö¶ÔÏó¡¢³ÌÐòÀ´ÑéÖ¤ÄãµÄ´úÂëÄÜÕý³£ÔËÐУ¿
½â¾ö·½°¸
µ±ÓÃsitu£¨»òÔÚÒ»¸ö·ÂÕæµÄ³ÌÐò»·¾³ÖУ©²âÊÔÒ»¸ö¶ÔÏó´ú¼Û²»·Æ»òÀ§ÄÑÖØÖØÊ±£¬¾Í¿ÉÓÃα¶ÔÏóÀ´Ä£ÄâÕâ¸öÐÐΪ¡£Î±¶ÔÏóÓÐÍ¬ÕæÊµ¶ÔÏóÒ»ÑùµÄ½Ó¿Ú£¬µ«È´ÄÜÌṩԤ±àÒëÏìÓ¦£¬Äܸú×Ù·½·¨µ÷Ó㬲¢ÑéÖ¤µ÷ÓôÎÐò¡£
α¶ÔÏóÊDzâÊÔµÄ“ÌØ±ðÁ¦Á¿”¡£ËûÃDZ»ÃØÃÜѵÁ·£¬ÉøÍ¸½øÄ¿±ê´úÂ룬ģÄâ²¢¼àÊÓͨÐÅ·½Ê½£¬»Ø±¨½á¹û¡£Î±¶ÔÏóÓÐÖúÓÚ²éÕÒºÍÏû³ý³ÌÐò©¶´²¢ÄÜÖ§³Ö¸ü¶àÕý³£µ÷ÊÔ»·¾³Ïµē·ÀΣÏÕ”²Ù×÷¡£
×¢£ºThe ServerStub
α¶ÔÏóģʽÊÇÁíÒ»ÖÖ²âÊÔģʽServerStubµÄÀ©Õ¹¡£ServerStubÄ£Ê½Ìæ´úÒ»¸ö×ÊÔ´²¢·µ»ØÆä·½·¨Ëùµ÷ÓõÄÏàÓ¦Öµ¡£µ±Æä²ÎÓëÖ¸¶¨´ÎÐòµÄ·½·¨µÄµ÷ÓÃʱServerStub¾Í³ÉÁËα¶ÔÏó¡£
Æä²¢·ÇÊÇÒ»¸öÉè¼ÆÄ£Ê½
±¾ÕÂÓëÆäËûÕ²»Í¬£¬ÒòΪα¶ÔÏóÊÇÒ»¸ö²âÊÔģʽ¶ø²»ÊÇÉè¼ÆÄ£Ê½¡£ÕâÀàËÆÓÚÒ»¸ö¸½¼ÓµÄÕ½ڣ¬µ«¶ÔËüµÄʹÓà ȷʵºÜÖµµÃÄãÄÉÈëµ½±àÂë½ø³ÌÖС£ÁíÒ»¸ö²»Í¬ÊÇÎÒÃDz»ÔÙ¹Ø×¢Õâ¸öģʽÈçºÎ±àÂëÖ®ÀàµÄ»ù´¡ÎÊÌ⣬¶øÊÇÇ¿µ÷ ÈçºÎÔÚSimpleTestÖÐʹÓÃα¶ÔÏó¡£
±¾ÕÂÏȾÙÒ»¸ö·Ç³£¼òµ¥µÄÀý×ÓÀ´Ê¾·¶SimpleTestÏÂα¶ÔÏóµÄ»ù±¾»úÖÆ¡£È»ºóÏòÄãÑÝʾÈçºÎʹÓÃα¶ÔÏó°ïÖúÖØ¹¹ÒÑÓдúÂëÓëÈçºÎ²âÊÔеĽâ¾ö·½°¸¡£
Ñù±¾´úÂë
α¶ÔÏóÊǶÔÏóÔÚ²âÊÔÖеÄÒ»¸öÌæ´úÆ·£¬ÓÃËü²âÊÔ´úÂë¸ü¼Ó¼ò±ã¡£ÀýÈç£¬Ìæ´úÒ»¸öÕæÊµµÄÊý¾ÝÁ¬½Ó——Õâ¸öÕæÊµµÄÊý¾ÝÁ¬½ÓÓÉÓÚһЩÔÒò¶ø²»ÄÜʵ¼ÊÁ¬½Ó——Äã¾Í¿ÉÒÔ´´½¨Ò»¸öα¶ÔÏóÀ´Ä£Äâ¡£ÕâÒâζ×Åα¶ÔÏóÐèҪ׼ȷµØ»ØÓ¦´úÂëÖÐËùµ÷ÓõÄÏàͬµÄÓ¦ÓóÌÐò½Ó¿Ú¡£
ÈÃÎÒÃÇ´´½¨Ò»¸öα¶ÔÏóÀ´Ìæ´úÒ»¸ö¼òµ¥µÄÃûΪAccumulatorµÄÀ࣬ÕâÊÇÒ»¸öÇóºÍµÄÀà¡£ÈçÏÂÊÇ×î³õµÄAccumulatorÀࣺ
|
// PHP4 |
| function calc_total($items, &$sum) { foreach($items as $item) { $sum->add($item); } } function calc_tax(&$amount, $rate=0.07) { return round($amount->total() * $rate,2); } |
µÚÒ»¸öº¯Êýcalc_total()ÓÃÒ»¸öÀۼӵ͝×÷ÇóһϵÁÐÖµµÄºÍ¡£ÏÂÃæÊǼòµ¥µÄ²âÊÔ£º
| class MockObjectTestCase extends UnitTestCase { function testCalcTotal() { $sum=& new Accumulator; calc_total(array(1,2,3), $sum); $this->assertEqual(6, $sum->total()); } } |
ÈÃÎÒÃǹØ×¢µÚ¶þ¸öÀý×Ó¡£¼ÙÉèʵÏÖÒ»¸öÕæÊµµÄÀÛ¼Ó¶¯×÷µÄ´ú¼ÛºÜ´ó¡£ÄÇôÓÃÒ»¸ö¼òµ¥µÄ¶ÔÏóÀ´Ìæ´úËü²¢»ØÓ¦Ïà¹Ø´úÂë¾ÍÊǺܺõÄ×ö·¨ÁË¡£Ê¹ÓÃSimpleTest£¬Äã¿ÉÒÔÓÃÈçÏ´úÂë´´½¨Ò»¸öαÀÛ¼Ó¶¯×÷£º
| Mock::generate(‘Accumulator’); class MockObjectTestCase extends UnitTestCase { // ... function testCalcTax() { $amount=& new MockAccumulator($this); $amount->setReturnValue(‘total’,200); $this->assertEqual( 14, calc_tax($amount)); } } |
ΪÁËʹÓÃα¶ÔÏ󣬾ßÓдú±íÐÔµÄ×ö·¨ÊÇÄãÇ××Ôдһ¸öÐÂÀࣨ²¢²»ÒªÇóÂíÉÏ×ö£©¡£ÐÒÔ˵ÄÊÇ£¬SimpleTestÓÐÒ»ÖÖÈÝÒ×µÄÊÖ¶ÎÀ´ÊµÏÖ Mock::generate() ·½·¨¡£
ÔÚÉÏÃæµÄÀý×ÓÖУ¬ÕâÖÖÊֶδ´½¨ÁËÒ»¸öÃûΪMockAccumulatorµÄÀàÀ´ÏìÓ¦ËùÓÐAccumulatorÀàµÄ·½·¨¡£ÁíÍ⣬αÀۼӵ͝×÷»¹ÓÐÆäËûÊÖ¶ÎÀ´²Ù×÷α¶ÔÏó×ÔÉíµÄʵÀý¡£ÀýÈç setReturnValue()¡£¸ø³öÒ»¸ö·½·¨ÃûºÍÒ»¸öÖµ£¬
setReturnValue()¾Í¿ÉÒԸıäα¶ÔÏó¶ø¸ø³ö¶ÔÓ¦·½·¨Ëùµ÷ÓõÄÖµ¡£Òò´Ë£¬ÕâÌõÓï¾ä$amount->setReturnValue(‘total’, 200)·µ»Ø200¶ø²»ÂÛºÎʱµ÷ÓÃÁËtotal()·½·¨¡£
Ò»µ©½øÐÐÍê³õʼ»¯¹¤×÷ºó£¬Äã¿ÉÒÔ´«µÝMockAccumulatorÀൽcalc_tax()º¯ÊýÀ´ÑÝʾһ¸öÔÚÕæÊµµÄAccumulator¶ÔÏó¿Õ¼äÖе͝×÷¡£
Èç¹ûÄãÖ¹²½ÓÚ´Ë——¼´ÓÃÒ»¸ö¶ÔÏóÀ´·µ»ØËùµ÷Óú¯ÊýµÄ“·â×°”ÏìÓ¦——ÄãÖ»ÊÇʹÓÃÁËServerStubģʽ¡£ ÓÃα¶ÔÏóÀ´ÑéÖ¤·½·¨µÄµ÷Óò»ÏÞÓÚ´Ë£¬ÒòΪËü¿ÉÒÔ²»ÏÞ´ÎÐòÓë´ÎÊý¡£
ÏÂÃæÊÇÒ»¸öͨ¹ý¶ÔÏóÀ´ÑéÖ¤“Êý¾ÝÁ÷”µÄÀý×Ó£º
| class MockObjectTestCase extends UnitTestCase { // ... function testCalcTax() { $amount=& new MockAccumulator($this); $amount->setReturnValue(‘total’,200); $amount->expectOnce(‘total’); $this->assertEqual( 14, calc_tax($amount)); $amount->tally(); } } |
ÕâÀïexpectOnce()·½·¨Ê¹ÓÃÁËÒ»¸ö×Ö·û´®£¬Ëü°üº¬ÄãÏëµ÷Óõķ½·¨Ãû ¡£¶øtally()ʵ¼ÊÉÏÓÃÀ´¼ì²éÄãµÄÏë·¨ÊÇ·ñʵÏÖ¡£ÕâÀÈç¹ûMockAccumulator::total()Ö»µ÷ÓÃÒ»´Î»ò²»µ÷Ó㬲âÊÔ½«Ê§°Ü¡£
ÔںܶàÇé¿öÏÂÄã¿ÉÒÔʹÓÃα¶ÔÏóµÄ”¸ú×Ù”ÌØÐÔ¡£ÀýÈ磬Èç¹ûÄã´«µÝÒ»¸ö¾ßÓÐÈý¸öÖµµÄÊý×éµ½calc_total()£¬Accumulator::add()ÊÇ·ñÒ²ÈçÄãËùÏëµÄµ÷ÓÃÁËÈý´ÎÄØ£¿
| class MockObjectTestCase extends UnitTestCase { // ... function testCalcTotalAgain() { $sum=& new MockAccumulator($this); $sum->expectOnce(‘add’); calc_total(array(1,2,3), $sum); $sum->tally(); } } |
ÄÇ£¬ÕâÀï·¢ÉúÁËʲô£¿´«µÝµ÷ÓõIJâÊÔʧ°Ü¡£SimpleTestµÄ´íÎóÏûÏ¢ÈçÏÂËùʾ£º
| MockObject PHP4 Unit Test 1) Expected call count for [add] was [1] got [3] at line [51] in testcalctotalagain in mockobjecttestcase FAILURES!!! Test cases run: 1/1, Passes: 2, Failures: 1, Exceptions: 0 |
´íÎóÏûÏ¢Ö¸³öÁ˾¡¹Üadd() ·½·¨±»µ÷ÓÃÈý´Î£¬µ«expectOnce()È´Ò»´ÎҲûÓõ½¡£È¡´úexpectOnce()µÄ¿ÉÐз½·¨ÊÇʹÓÃexpectCallCount()¡£
| class MockObjectTestCase extends UnitTestCase { // ... function testCalcTotalAgain() { $sum=& new MockAccumulator($this); $sum->expectCallCount(‘add’, 3); calc_total(array(1,2,3), $sum); $sum->tally(); } } |
α¶ÔÏó°çÑÝÁËÒ»¸öÑÝÔ±µÄ½ÇÉ«——Õâ¸ö½ÇÉ«ÓÉSeverStubÌṩºÏÀíµÄ²âÊÔÊý¾ÝÀ´ÏìÓ¦·½·¨µÄµ÷Ó×—²¢ÇÒ×÷Ϊһ¸öÆÀÅеĽÇÉ«£¬ÑéÖ¤Ëùµ÷Óõķ½·¨ÊÇ·ñ·ûºÏÔ¤Ïë¡£
ÖØ¹¹ÒÑÓгÌÐò
ÏÂÃæÈÃÎÒÃÇÓÃα¶ÔÏóÀ´°ïÖúÖØ¹¹Ò»¸öÒÑÓгÌÐò¡£¿¼ÂÇÒ»¸ö¼òµ¥µÄ½Å±¾£¬Ëü¿ÉÒÔÄ£ÄâÄãÔÚÎÞÊýµÄPHP³ÌÐòÖÐËùÆÚÍûµÄÐÐΪ£ºÀýÈçÒ»¸öµ±¼ì²éµ½ÄãδµÇ¼ʱҪÇóµÇ¼µÄÒ³Ãæ£»Óë´ËÀàËÆµÄ»¹ÓÐ±íµ¥´¦ÀíÒ³Ãæ£»ËüÄÜÔڳɹ¦µÇ¼ºóÏÔʾ²»Í¬ÄÚÈݲ¢ÌṩµÇ³öµÄ¹¦ÄÜ¡£ ÈÃÎÒÃÇдһ¸öÕâÑùµÄÒ³Ãæ¡£Ê×ÏÈ£¬¶Ô»¹Î´µÇ¼µÄÓû§ÏÔʾһ¸öµÇ¼±íµ¥¡£
| <html> <body> <form method=”post”> Name:<input type=”text” name=”name”> Password:<input type=”password” name=”passwd”> <input type=”submit” value=”Login”> </form> </body> </html> |
½Ó×Å£¬ÏÔʾµÇ¼³É¹¦ºóµÄÄÚÈÝ£º
| <html> <body>Welcome <?php echo $_SESSION[‘name’]; ?> <br>Super secret member only content here. <a href=http://www.chinaz.com/program/2008/0613/”<?php echo SELF; ?>?clear”>Logout</a> </body> </html> |
¼ÓÈë±íµ¥´¦ÀíµÄ¹¦ÄÜ£¬session£¨»á»°£©¿ªÊ¼£¬»¹ÓеdzöµÄ¹¦ÄÜ£¬ÕûÌå¿´ÆðÀ´Ó¦¸ÃÀàËÆÕâÑù£º
|
session_start(); |
ÀýÈ磬Èç¹ûÄãÖ±½Ó¾ÍÓÃÁË$_SESSION£¬¼´Òâζ×ÅÖ»ÓÐÒ»ÖÖ;¾¶¿ÉÒÔ²âÊÔÕâ¸ö´úÂ룬¾ÍÊǸıä$_SESSION¡£Èç¹ûÄãÍüÁ˽«$_SESSION¸Ä»ØÏÈǰÒÑÖªµÄ״̬£¬¸÷ÖÖ²âÊÔ¼ä¾Í»á»¥Ïà¸ÉÈÅ¡£
Ò»¸öºÃµÄ½â¾ö·½·¨ÊÇ·â×°$_SESSIONµ½ÁíÒ»¸öÀàÖУ¬´«µÝËù·â×°ÀàµÄʵÀýµ½ÈκÎÏëÒª·ÃÎÊ$_SESSIONµÄ¶ÔÏó¡£Èç¹ûÄã´´½¨ÁËÒ»¸öÒÑ·â×°¶ÔÏóµÄα¶ÔÏóÓÃÓÚ²âÊÔ£¬ÄãÄܹ»ÍêÈ«¿ØÖƶÔÏó¶ÔËùµ÷Ó÷½·¨µÄÏìÓ¦£¨¾ÍÏñServerStubÄÇÑù£©²¢ÇÒÄãÄܺËʵËüÊÇÈçºÎµ÷Óõģ¨ÄÇÕýÊÇ´´½¨Î±¶ÔÏóµÄÄ¿µÄ£©¡£
¾ß±¸ÁËÕâ¸ö˼Ï룬ÈÃÎÒÃÇ¿´¿´ÈçºÎ·â×°$_SESSIONÖ®ÀàµÄÈ«¾Ö±äÁ¿¡£
|
class Session { |
ÄãÒ²Ðí×¢Òâµ½Á˹¹Ô캯Êýµ÷ÓÃÁËSession::init()·½·¨¡£ÎªÊ²Ã´Õâ¸ö·½·¨²»Êǹ¹Ô캯ÊýµÄÒ»²¿·ÖÄØ£¿ÕâÑù·Ö¿ªµÄºÃ´¦ÊÇÄãÄܾ²Ì¬µ÷ÓÃËü²¢È·±£sessionÒѾ¿ªÊ¼¡£ÏÂÃæÊÇÒ»¸öÈçºÎʹÓøÃÀàµÄÀý×Ó¡£
| Session::init(); $page=& new PageDirector(new Session); |
´ó²¿·Ö²âÊÔ·½ÃæµÄÎÄÏ׺ÜÍÆ³çα¶ÔÏó²¢½¨ÒéÄãÇ××Ôдһ¸ö¡£Èç¹ûÄã´òËãÄÇÑù×ö£¬¿ªÊ¼²âÊÔʱÄã¾ÍÖ»ÐèÒª³äʵÄÇЩÄãÐèÒªµÄ·½·¨¾Í¿ÉÒÔÁË¡£Æ©È磬һ¸öÓÃÓÚ´¦Àí´úÂëµÄServerStubµÄSessionÀàºÜ¿ÉÄÜÊÇÕâÑùµÄ£º
| class MyMockSessionUser1 { function isValid($key) { return (‘user_id’==$key) ? true : false; } function get($key) { if (‘user_id’==$key) { return 1; } } } |
ÐÒÔ˵ÄÊÇ£¬Äã¿ÉÒÔÓÃSimpleTestÀ´±ÜÃâÄÇЩÒ×·¶µÄ´íÎó¡£Mock::generate()·½·¨ÔÊÐíÄã´´½¨Ò»¸öÀàÀ´ÊµÀý»¯»ò¶¯Ì¬µØÅäÖÃÄãÏëÒªµÄ½á¹û¡£
×¢£ºÎ±¶ÔÏó¼¼Êõ
SimpleTestËùʹÓõķ½·¨½öÊÇα¶ÔÏóµÄ¶àÖÖÓ÷¨Ö®Ò»¡£Î±¶ÔÏóµÄ´úÂë´«µÝÊÇÁíÒ»ÖÖ¡£Ëæ×ÅPHP5µÄµ½À´£¬ÄãÒ²ÐíÄÜ¿´µ½Î±¶ÔÏóÒÔ¶ÔÏóÖеÄ__call()·½·¨À´Ö´ÐС£
ÒÔÏÂÊÇÈçºÎÓÃSimpleTestÉú³ÉµÄα¶ÔÏóÀ´²âÊÔ²¢Öع¹MyMockSessionUser1ÀࣨÈçÉÏÀýÖУ©¡£
| Mock::Generate(‘Session’); class PageDirectorTestCase extends UnitTestCase { function testSomethingWhichUsesSession() { $session=& new MockSession($this); $session->setReturnValue(‘isValid’, true); $session->setReturnValue(‘get’, 1); // ... } } |
¸ü½øÒ»²½Ëµ£¬ÄãÄÜËæÐÄËùÓûµÄÉèÖúÎÖÖ·½·¨±»µ÷ÓÃÒÔ¼°µ÷ÓöàÉٴΡ£ÄãÉõÖÁ¿ÉÒÔÑéÖ¤ÄÇЩ¸ù±¾²»¸Ã±»µ÷Óõķ½·¨¡£
ÏÂÃæÊÇÒ»¸öÀ©Õ¹Ð͵IJâÊÔ£¬ËüÓÃÀ´½¨Á¢ºÍÑéÖ¤ÄÇЩ¸´ÔÓµÄÉè¼Æ¡£
| class PageDirectorTestCase extends UnitTestCase { function testSomethingWhichUsesSession() { $session=& new MockSession($this); $session->setReturnValue(‘isValid’, true); $session->setReturnValue(‘get’, 1); $session->expectOnce(‘isValid’, array(‘user_id’)); $session->expectOnce(‘get’, array(‘user_id’)); $session->expectNever(‘set’); // the actual code which uses $session $session->tally(); } } |
ʹÓÃα¶ÔÏóµÄÔÒòºÜ¶à£¬·½·¨Ò²¶àÑù»¯¡£µ«ÔÚÎÒÃǼÌÐøÇ°£¬ÈÃÎÒÃǰÑÁíÍâµÄһЩÀà¼ÓÈë½øÀ´£¬Ê¹ÆäÀ´ÁúÈ¥Âö¸ü¼ÓÇå³þ¡£
½ÓÏÂÀ´µÄÒ»²¿·ÖÊÇÖØ¹¹ÒÑÓнű¾£¬´´½¨Ò»¸öÓÃÓÚ¼ì²éÓû§ÊÇ·ñÓÐÏàӦȨÏÞµÄÃûΪUserLoginµÄÀà¡£
| class UserLogin { var $_valid=true; var $_id; var $_name; function UserLogin($name) { switch (strtolower($name)) { case ‘admin’: $this->_id=1; $this->_name=‘admin’; break; default: trigger_error(“Bad user name ‘$name’”); $this->_valid=false; } } function name() { if ($this->_valid) return $this->_name; } function Validate($user_name, $password) { if (‘admin’==strtolower($user_name) && ‘secret’==$password) { return true; } return false; } } |
×îºóÒ»²¿·ÖÊÇ´´½¨ÏìÓ¦¡£ÎªÁË×îÖÕÔÚä¯ÀÀÆ÷ÖÐÏÔʾ£¬ÎÒÃDZØÐë´¦ÀíÄDz»¶ÏÔö³¤µÄHTMLÄÚÈÝ£¬Èç¹û±ØÒªµÄ»°ÎÒÃÇÒ²»áÌÖÂÛHTTPÖØ¶¨Ïò¡££¨ÄãÒ²¿ÉÒÔÖ´ÐÐÆäËûµÄhttpÍ·µÄ²Ù×÷——ÕâÑù˵ÊÇΪÁËÄܹ¹Òþ²ØËü——ÔÚÒ»¸ö³ÉÊìµÄ×ö·¨ÖУ¬µ«ÕâÀïʹÓõÄÊÇÒ»¶Î¸ü¼òµ¥µÄ´úÂ룬ÊÇΪÁËʹÀý×ÓÈÝÒ×Àí½âÓë¹Ø×¢¡££©
| class Response { var $_head=’’; var $_body=’’; function addHead($content) { $this->_head .=$content; } function addBody($content) { $this->_body .=$content; } function display() { echo $this->fetch(); } function fetch() { return ‘<html>’ .’<head>’.$this->_head.’</head>’ .’<body>’.$this->_body.’</body>’ .’</html>’; } function redirect($url, $exit=true) { header(‘Location: ‘.$url); if ($exit) exit; } } |
¸ø³öÁËÕâЩģ¿éºó£¬Ò²ÊÇʱºò½«ÕâЩпª·¢µÄ¡¢ÒѲâÊÔµÄ×é¼þ¾ÛºÏµ½Ò»¸öÒ³ÃæÖÐÁË¡£ÈÃÎÒÃÇдһ¸ö×îÖÕµÄÀàÀ´Ðµ÷Õâ¸öÒ³ÃæµÄËùÒÔÐÐΪ£¬È¡¸öºÏÊʵÄÃû×ÖPageDirector¡£ÀàPageDirector¾ßÓÐÒ»¸öºÜ¼òµ¥µÄÔËÓóÌÐò½Ó¿Ú£ºÄãÔÚʵÀý»¯ºó¿ÉÒÔÓõ÷ÓÃËüµÄrun()·½·¨¡£
Õâ¸ö“bootstrap”ÎļþÔËÐÐгÌÐòʱӦÈçÏÂËùʾ£º
| <?php require_once ‘classes.inc.php’; define(‘SELF’, ‘http://www.example.com/path/to/page.php’); $page=& new PageDirector(new Session, new Response); $page->run(); ?> |
¸ÃÎļþ°üº¬ÁËËùÐèµÄÒѶ¨ÒåÀ࣬²¢Îª×Ô¼º¶¨ÒåÁËÒ»¸ö³£Á¿£¬¸øPageDirectorÀࣨÆäÓÃÓÚ´«µÝÀàSession ºÍÀàResponseËùÒÀÀµµÄʵÀýÀ´×é³É¹¹Ô캯Êý£©´´½¨ÁËÒ»¸öʵÀýÀ´Ö´ÐÐPageDirector::run()·½·¨¡£
ÏÖÔÚÈÃÎÒÃÇÀ´´´½¨Ò»Ð©²âÊÔµÄʵÀýÀ´Ïêϸ˵Ã÷ÖØ¹¹ºóµÄÔËÓóÌÐòÓ¦¸ÃÓеŦÄÜ¡£
| require_once ‘simpletest/unit_tester.php’; require_once ‘simpletest/reporter.php’; require_once ‘simpletest/mock_objects.php’; require_once ‘simpletest/web_tester.php’; require_once ‘classes.inc.php’; Session::init(); class PageWebTestCase extends WebTestCase { } class ResponseTestCase extends UnitTestCase { } class UserLoginTestCase extends UnitTestCase { } class SessionTestCase extends UnitTestCase { } class PageDirectorTestCase extends UnitTestCase { } $test=new GroupTest(‘Application PHP4 Unit Test’); $test->addTestCase(new PageWebTestCase); $test->addTestCase(new ResponseTestCase); $test->addTestCase(new UserLoginTestCase); $test->addTestCase(new SessionTestCase); $test->addTestCase(new PageDirectorTestCase); |
Õâ¶Î´úÂë»ò¶à»òÉÙµÄչʾÁËÒ»¸öµäÐ͵ÄÔËÓóÌÐòµÄ²âÊÔÎļþ¸ÃÊǺÎÖÖÄ£Ñù¡£ËüÒ»¿ªÊ¼¾Í°üº¬ÁËһЩSimpleTestÎļþ£¬Ò²°üÀ¨ÁËÓÃα¶ÔÏóÀ´²âÊÔµÄmock_object.phpÎļþ¡£½Ó×Å£¬ÄÇЩ¸¨ÖúÀà±»°üº¬½øÀ´£¬·½·¨Session::init()±»µ÷Óã¬seesion¿ªÊ¼¡£
½ô½Ó×ŵÄÈ«ÊÇÒÔ“°²È«ÎÞº¦”ΪĿ±ê¶ø¿ªÊ¼µÄ²âÊÔʵÀý£¬ÀàWebTestCaseÈ·±£ËùÓгÌÐò°´ÒªÇóÖ´ÐУ¬ È»ºóÊǵ¥¶ÀµÄÓÃÓÚÐÂÉè¼ÆµÄÀàµÄ²âÊÔ£¨¾¡¹ÜÕâÖÖÀà±¾Õ²»»áÏêÊö£©¡£×îºóÊÇÎÒÃǽÓÏÂÈ¥»áÌÖÂÛµÄPageDirectorTestCaseÀà¡£
ÀàPageDirectorµÄºËÐÄÈÎÎñÊÇе÷ÀàSessionºÍÀàResponseµÄ¶ÔÏ󣬲úÉú×îÖÕµÄÍøÒ³Êä³ö½á¹û¡£
| Mock::Generate(‘Session’); Mock::Generate(‘Response’); define(‘SELF’, ‘testvalue’); class PageDirectorTestCase extends UnitTestCase { // ... } |
ÔÚÕâ¶Î´úÂëµÄÒ»¿ªÊ¼£¬Mock::generate()´´½¨ÁËα¶ÔÏóÀàµÄ¶¨Òå²¢¶¨ÒåÁËÒ»¸öºóÃæ½«ÒªÓõ½µÄ³£Á¿¡£
¼ÙÉè¶ÔÀàSession ºÍÀà ResponseµÄ²âÊÔÒѾ´æÔÚ£¬ÏÂÒ»²½¾ÍÊÇ´´½¨Î±SessionÀ´Ä£ÄâÀà SessionµÄ״̬¡£Õâ¸öα¶ÔÏóµÄÉèÖúÍÎÒÃÇÒ»¿ªÊ¼ËùÑÝʾµÄÀý×Ó¼«ÆäÀàËÆ¡£
ÒòΪPageDirector::run()·½·¨Õý»ØÏÔÄÚÈÝ£¬Äã¿ÉÒÔÓÃÊä³ö»º´æÄÚÈݵİ취À´²¶»ñËü£¬¿´¿´ÊÇ·ñÕýÈ·¡£
| class PageDirectorTestCase extends UnitTestCase { // ... function TestLoggedOutContent() { $session=& new MockSession($this); $session->setReturnValue(‘get’, null, array(‘user_name’)); $session->expectOnce(‘get’, array(‘user_name’)); $page=& new PageDirector($session, new Response); ob_start(); $page->run(); $result=ob_get_clean(); $this->assertNoUnwantedPattern(‘/secret.*content/i’, $result); $this->assertWantedPattern(‘/<form.*<input[^>]*text[^>]*’ .’name.*<input[^>]*password[^>]*passwd/ims’ ,$result); $session->tally(); } } |
Õâ¶Î´úÂëÖ¤Ã÷ÁËÔÚSimpleTestÖÐʹÓÃα¶ÔÏóµÄ±ØÒªÐÔ¡£ÎÒÃÇÀ´¿´¿´ÆäÖд´½¨Î±¶ÔÏóµÄÒ»ÐдúÂë$session=&new MockSession($this)¡£Äã¿ÉÒÔʹÓü̳Ð×ÔSimpleStubÀࣨ²Î¼ûhttp://simpletest.sf.net/SimpleTest/MockObjects/SimpleStub.html#sec-methodsummary)µÄ·½·¨À´´´½¨ÄãËùÏ£ÍûµÄ´Ó¶ÔÏó(ÈçͬÄãÔÚ²âÊÔ´úÂëʱËù×öµÄÄÇÑù)·µ»ØµÄ½á¹û.ÏÂÒ»²½£¬ÊµÀý»¯PageDirectorÀಢÓÃMockSession´úÌæÕýʽʹÓÃʱµÄÀàÀ´ÊµÀý»¯Ïà¹Ø´úÂë¡£
×¢£ºsetReturnValue()·½·¨
setReturnValue()·½·¨Í¨¹ýÖ¸¶¨µ±Î±¶ÔÏóµÄÌØ¶¨·½·¨±»µ÷ÓÃʱ·µ»ØºÎÖµÀ´ÈÃα¶ÔÏóÒÔÒ»¸ö“ÌæÉ픵ÄÉí·ÝÈÚÈë´úÂë¡£ÒѾÓÐÁËһЩÕâÖÖ·½·¨µÄ±äÌ壺±ÈÈçÖ¸¶¨ÒÔÒ»¶¨´ÎÐò·µ»ØÒ»ÏµÁÐÖµµÄ×ö·¨£¬»¹ÓÐÒÔ²ÎÊý´úÌæÖµÀ´·µ»Ø½á¹ûµÄ×ö·¨¡£
expectOnce()·½·¨
expectOnce()·½·¨Í¨¹ý½¨Á¢Ò»Ð©¼ÙÏ룬ÕâЩ¼ÙÏëÊǹØÓÚʲôʱºò·½·¨±»µ÷ÓÃÒÔ¼°¶à¾Ãµ÷ÓÃÒ»´Î£¬À´ÔÊÐíÄãµÄα¶ÔÏóÒÔ“ÅúÆÀÕß”µÄ½ÇÉ«À´²âÊÔ´úÂë¡£ÕâЩ¼ÙÏëµ±ÄãÔÚ²âÊÔÖе÷ÓÃα¶ÔÏóµÄtally()·½·¨Ê±»á±»±¨¸æ¡£
| class PageDirector { var $session; var $response; function PageDirector(&$session, &$response) { $this->session=& $session; $this->response=& $response; } } |
ÒòΪPageDirectorÀàÈÏΪ×Ô¼º²»ÊÇ´¦ÓÚÒ»¸ö²âÊÔ»·¾³¶øÊÇ´¦ÓÚÒ»¸öÕæÊµÕý³£µÄÔËÓóÌÐò»·¾³ÖУ¬Ëü»ØÏÔ½á¹ûµ½ä¯ÀÀÆ÷¡£¼ÈÈ»Äãʵ¼ÊÉÏÔÚ²âÊÔʱ²¢²»Ï£ÍûÕâ¸ö¶¯×÷£¬Äã¾Í¿ÉÒÔͨ¹ýPHPÊä³ö»º´æµÄÌØÐÔ£¨²Î¼ûhttp://php.net/outcontrol£©À´²¶»ñÖ´ÐÐʱËüÍùä¯ÀÀÆ÷·¢ËÍÁËʲô¡£
| class PageDirector { // ... function run() { if (!$this->isLoggedIn()) { $this->showLogin(); } this->response->display(); } function isLoggedIn() { return ($this->session->get(‘user_name’)) ? true : false; } function showLogin() { $this->response->addBody(‘<form method=”post”>’); $this->response->addBody(‘Name:<input type=”text” name=”name”>’); $this->response->addBody(“\n”); $this->response->addBody( ‘Password:<input type=”password” name=”passwd”>’); $this->response->addBody(“\n”); $this->response->addBody(‘<input type=”submit” value=”Login”>’); $this->response->addBody(‘</form>’); } } |
ÏÂÃæµÄ´úÂë¶ÎÑÝʾÁË»º´æÊä³ö±»Öع¹ÎªrunPage·½·¨µÄ½á¹û£¬Ëü¸øÈ˵ĸоõ¾ÍÏñÊǵ±Óû§µÇ¼ʱÁíÒ»¸ö¶ÔÊä³öµÄ²âÊÔ¡£
| class PageDirectorTestCase extends UnitTestCase { // ... function TestLoggedOutContent() { $session=& new MockSession($this); $session->setReturnValue(‘get’, null, array(‘user_name’)); $session->expectOnce(‘get’, array(‘user_name’)); $page=& new PageDirector($session, new Response); $result=$this->runPage($page); $this->assertNoUnwantedPattern(‘/secret.*content/i’, $result); $this->assertWantedPattern(‘/<form.*<input[^>]*text[^>]*’ .’name.*<input[^>]*password[^>]*passwd/ims’ ,$result); $session->tally(); } function TestLoggedInContent() { $session=& new MockSession($this); $session->setReturnValue(‘get’, ‘admin’, array(‘user_name’)); $session->expectAtLeastOnce(‘get’); $page=& new PageDirector($session, new Response); $result=$this->runPage($page); $this->assertWantedPattern(‘/secret.*content/i’, $result); $this->assertNoUnwantedPattern(‘/<form.*<input[^>]*text[^>]*’ .’name.*<input[^>]*password[^>]*passwd/ims’ ,$result); $session->tally(); } function runPage(&$page) { ob_start(); $page->run(); return ob_get_clean(); } } |
½ÓÏÂÀ´£¬½«¼ÓÈëÒ»¸ö¼ì²éÌõ¼þµ½PageDirector::run()·½·¨À´¿´¿´Óû§ÊÇ·ñÒѾµÇ¼²¢¾ö¶¨ÏÔʾʲôģ°å£º
| class PageDirector { // ... function run() { if ($this->isLoggedIn()) { $this->showPage( new UserLogin($this->session->get(‘user_name’))); } else { $this->showLogin(); } $this->response->display(); } function showPage(&$user) { $vars=array( ‘name’=> $user->name() ,’self’=> SELF ); $this->response->addBodyTemplate(‘page.tpl’, $vars); } } |
page.tpl¿´ÉÏÈ¥¿ÉÄÜÏñÕâÑù£º
| Welcome <?php echo $name; ?> <br>Super secret member only content here. <a href=http://www.chinaz.com/program/2008/0613/”<?php echo $self; ?>?clear”>Logout</a> |
´Ëʱ£¬MockSession°çÑÝÁËServerStubµÄ½ÇÉ«À´¿ØÖƾö¶¨Óû§ÊÇ·ñµÇ¼µÄÌõ¼þ¡£ËüµÄ¹¦ÄÜÒ²ÀàËÆÆÀÅÐÕߣ¬¾ö¶¨Õâ¸öÐÅÏ¢ÊÇ·ñͨ¹ýÈçÏÂÁ½¸ö;¾¶±»ÕýÈ·µÄʹÓãºÒ»¸öÊÇÃ÷È·µØ±»Ô¤Ïȶ¨Ò岢ͨ¹ýtally()±»ÑéÖ¤£¬ÁíÒ»¸öÊDz»Ö±½ÓµÄÉú³ÉÕýÈ·µÄÊä³ö£¬¶øÊÇͨ¹ýServerStub·µ»ØµÄÖµÀ´Éú³É¡£
ΪÁ˼ÌÐøÖØ¹¹Õâ¶Î´úÂ룬ÏÂÒ»²½ÒªÌøµ½Ç°ÃæµÄ½ø³Ì¡£½«Òª×öÁ½¸ö¶¯×÷£ºÇå³ýÒѾµÇ¼µÄÓû§ºÍÑéÖ¤µÇÂ¼Ò³ÃæÌá½»µÄÓû§ÃûºÍÃÜÂëÊÇ·ñ´æÔÚ¡£
ÈÃÎÒÃÇ´Ó×¢Ïú¹¦ÄÜÉÏ¿ªÊ¼£º
|
class PageDirectorTestCase extends UnitTestCase { |
ÔÚÕâ¶Î´úÂëÖУ¬responseÊǸöα¶ÔÏó£¬È»¶ø£¬Ò»µ©ÔÚResponse::redirect()·½·¨Öе÷ÓÃÁËexit()£¬½Å±¾½«»áÍ£Ö¹Ö´ÐС£ÓÉÓÚα¶ÔÏóµÄ´æÔÚ£¬Äã¿ÉÒÔºËʵ·½·¨ÊÇ·ñ±»µ÷Óúͷ½·¨´«»ØÁËʲô²ÎÊý£¬ÇÒ²»»á²úÉúÈκθºÃæÓ°Ïì——Èç½Å±¾Í£Ö¹——»ò±»Êµ¼ÊÖ´ÐС£
ÏÂÃæÊÇÊÇһЩ°ïÖúÄãÈÏʶ²âÊÔ¹¦ÄܵĴúÂ룺
| class PageDirector { // ... function run() { $this->processLogin(); if ($this->isLoggedIn()) { $this->showPage( new UserLogin($this->session->get(‘user_name’))); } else { $this->showLogin(); } $this->response->display(); } function processLogin() { if (array_key_exists(‘clear’, $_REQUEST)) { $this->session->clear(‘user_name’); $this->response->redirect(SELF); } } } |
×îºóÊǶԵǼ±íµ¥µÄ´¦Àí½øÐеIJâÊÔ¡£
|
class PageDirectorTestCase extends UnitTestCase { |
ÈçÏÂÊÇʵÏÖÉÏÃæ²âÊÔËùÒªÇóÌØÐԵĴúÂ룺
|
class PageDirector { |
Õâ¶Î³ÌÐòÒÑ¾ÖØ¹¹¶øÇÒÒ²Óгä·ÖµÄ²âÊÔ£¬Òò´Ë¿ÉÒÔ¶ÔÆä½øÐÐһЩ¸½¼ÓµÄÖØ¹¹À´Çå³ýÏñÖ÷½Å±¾·ÃÎÊSessionÀ࣬²éѯ²»¾UserLoginÀàÈϿɵÄ×ֶζøÈ¥·ÃÎÊ‘user_name’×ֶΣ¬¼°session±»µ±³É×ÊÔ´µ÷ÓõȵÄС벡¡£
µ±$_REQUESTÕâ¸ö³¬¼¶±äÁ¿±»·âװΪһ¸öÀàËÆSessionÀàµÄ×ÊÔ´ÒÔ±ãÓëα¶ÔÏóµÄ´´½¨Ê±£¬ÎªºÎÈôúÂë·ÃÎÊËü£¿Õâ¶Î ´úÂëÓкܶàÎÊÌ⣺µ«Ëü±Ï¾¹ÊÇijÖÖÈËΪµÄÓÃÀ´Öð½¥Á˽âÕâЩ¸ÅÄîµÄÀý×Ó£¬ËüÊÇΪ´Ë¶ø±»´´ÔìµÄËùÒÔÄã²»±ØÉ¡£
¸üÎªÖØÒªµÄÊÇ£¬ÄãÒѾѧ»áÀûÓÃα¶ÔÏó²âÊÔģʽÀ´·ÖÀë´úÂ룬ÒÔ¼°ÔÚ²âÊÔÖзÖÀë$_SESSIONÖ®ÀàµÄ×ÊÔ´ºÍ±ÜÃâÏ໥¹ØÁªµÄ¶ÔÏó£¨Èç°üº¬ÔÚResponseÀàÖеÄexit()£©²úÉú²»Ï£ÍûµÄ½á¹û¡£
ÎÊÌâ
ʹÓÃα¶ÔÏóÀ´²âÊÔ´úÂë¿ÉÒÔÈÃÄã·ÖÀëËù¿ª·¢µÄ´úÂë¡£Äã¿ÉÒÔÏû³ý¸ºÃæÓ°ÏìºÍDZÔÚµÄÎÊÌ⣬¼«´óµØ¼õÉÙÄãÔÚÕû¸ö²âÊÔ¹¤×÷ÖÐËù»¨µÄʱ¼ä¡£ÕâÊÇÒ»¸öºÃÏûÏ¢£¬ÒòΪÈç¹ûÄ㻨ÔÚ²âÊÔÉϵÄʱ¼äÔ½¶à£¬ÒÔºó¾Í»áԽʡÊ£¬²¢ÇÒÄãÒ²»áÏ£Íû²âÊÔ²»ÊÇÖ»×öÒ»´Î£¬Ó¦¸ÃÄܹ»±»Öظ´½øÐС££¨Òë×¢£ºÕâ¾äÖ±ÒëÌ«±ðŤ£¬ËùÒÔ¼ÓÁËЩʹÆäͨ˳µÄÄÚÈÝ¡££©
ÔÚÐÂÖØ¹¹µÄ³ÌÐòÖÐÈÔÈ»»áÓÐÐí¶à©¶´¡£±ÈÈç$_REQUEST±äÁ¿Ó¦¸ÃÓÉÒ»¸öÀàÀ´·â×°ÒÔ±ãÓÚʹÓÃα¶ÔÏó²âÊÔ¡£ÓÖÈç showLogin()·½·¨µÄÖØÐµ÷Óá£ÔÙÈçËùÓÐÄÇЩaddBody()·½·¨µÄµ÷Óÿ´ÆðÀ´ÊÇÈç´Ë»ìÂÒ¡£
ÕâÖÖ±à³Ì·ç¸ñµÄÁíÒ»¸öȱµãÊÇÄ㽫ÎÞ·¨Ê¹ÓÃÈκÎËù¼û¼´ËùµÃµÄHTML±à¼¹¤¾ß£¬ÕâÊÇÒòΪËùÓÐHTML´úÂë¶¼±»°üº¬ÔÚPHPµÄ·½·¨µ÷ÓÃÖÐÁË¡£ÎªÁ˱ÜÃâÕâЩÏÞÖÆ£¬Äã¿ÉÒÔ¼ÓÈëÒ»¸ö¼òµ¥µÄ»ùÓÚPHPµÄÄ£°å»úÖÆ¡£Äã¿ÉÒÔÕâÑùÒýÈëÄ£°åÎļþ£º
| <form method=”post”> Name:<input type=”text” name=”name”> Password:<input type=”password” name=”passwd”> <input type=”submit” value=”Login”> </form> |
È»ºóÐèҪʹÓÃÒ»¸ö·½·¨À´µ÷ÓÃËü£º
| class Response { // ... function addBodyTemplate($template, $vars=array()) { if (file_exists($template)) { extract($vars); ob_start(); include $template; $this->_body .=ob_get_clean(); } } } |
ºÜÃ÷ÏԵģ¬ÊÀÉÏûÓÐ×îÍêÃÀµÄÄ£°åÒýÇæ£¬µ«Ëüȷʵʹ±¾ÕµÄʾÀý´úÂ뾫¼òÕû½àÁË¡£
ÔÚGoFÖÐÕâÖÖ°´ÈÎÎñ½øÐзָôµÄ¸ÅÄîÊDZ»¹ÄÀøµÄ£º
“·Ö¸ôÉè¼ÆÄ£Ê½Ï¶ÔÏó±»´´½¨ºó£¬Æä×ÓÀàµÄ´´½¨¹ý³Ì¾Í¿ÉÒÔ²»ÔÙ¹Ø×¢ÁË¡£”
ÒÔÉÏËù·ÖÏíµÄÊǹØÓÚ¡¶PHPÉè¼ÆÄ£Ê½½éÉÜ¡·µÚÁùÕ α¶ÔÏóģʽ£¬ÏÂÃæÊDZà¼ÎªÄãÍÆ¼öµÄÓмÛÖµµÄÓû§»¥¶¯£º
¡¡¡¡Ïà¹ØÎÊÌ⣺±à³ÌÉè¼ÆÄ£Ê½,23ÖÖÉè¼ÆÄ£Ê½Ôõôѧ°¡,ÐèÒªÄÇÖÖͨË×...
¡¡¡¡´ð£ºÍ¨Óñà³ÌÉè¼ÆÄ£Ê½¹²23ÖÖ-Ò×ѧƪ 1¡¢¹¤³§Ä£Ê½-×·MMÉÙ²»ÁËÇë³Ô·¹ÁË,Âóµ±À͵靈áºÍ¿ÏµÂ»ùµÄ¼¦³á¶¼ÊÇMM°®³ÔµÄ¶«Î÷,ËäÈ»¿ÚζÓÐËù²»Í¬,µ«²»¹ÜÄã´øMMÈ¥Âóµ±ÀÍ»ò¿ÏµÂ»ù,Ö»¹ÜÏò·þÎñԱ˵¡±À´Ëĸö¼¦³á¡±¾ÍÐÐÁË.Âóµ±ÀͺͿϵ»ù¾ÍÊÇÉú²ú¼¦³áµÄ 2¡¢½¨Ôìģʽ-MM... >>Ïêϸ
¡¡¡¡Ïà¹ØÎÊÌ⣺PHPµÄµ¥Ì¬Éè¼ÆÄ£Ê½
¡¡¡¡´ð£º¶ÔÓÚjavaת¹ýÀ´³ÌÐòԱ˵Êǵ¥Ì¬Éè¼ÆÄ£Ê½£¬ÔÚPHPÉÏͨ³£ËµÊǵ¥Àýģʽ£¬Ëµ·¨²»Ò»Ñù£¬ÊÖ²áÉÏÒ²ÓнéÉÜ£º µ¥Àýģʽ£¨Singleton£©ÓÃÓÚΪһ¸öÀàÉú³ÉÒ»¸öΨһµÄ¶ÔÏó¡£×î³£Óõĵط½ÊÇÊý¾Ý¿âÁ¬½Ó¡£ ʹÓõ¥ÀýģʽÉú³ÉÒ»¸ö¶ÔÏóºó£¬¸Ã¶ÔÏó¿ÉÒÔ±»ÆäËüÖÚ¶à¶ÔÏóËù... >>Ïêϸ
¡¡¡¡Ïà¹ØÎÊÌ⣺½éÉܼ¸¸öÄã±È½ÏÊìϤµÄÉè¼ÆÄ£Ê½,²¢¼òµ¥½éÉÜËüÃÇÊÇÈç...
¡¡¡¡´ð£ºÈçºÎ×öºÃ¼ô¼ÄØ£¿Ôڴ˱ÊÕß̸̸×Ô¼ºµÄ¹Ûµã£º¼ô¼¾ÍÊǽ«²»·ûºÏÖ÷ÌâµÄ²¿·Öɾ³ý²¢ÕâÀﻹ½éÉܼ¸¸ö¹ý¶ÉЧ¹ûµÄ²é¿´¼¼ÇÉ£ºÔÚTransitionsÃæ°åµÄ´°¿Ú¿ØÖƲ˵¥ÖУ¬Ñ¡Ôñ >>Ïêϸ
- ÆÀÂÛÁÐ±í£¨ÍøÓÑÆÀÂÛ½ö¹©ÍøÓѱí´ï¸öÈË¿´·¨£¬²¢²»±íÃ÷±¾Õ¾Í¬ÒâÆä¹Ûµã»ò֤ʵÆäÃèÊö£©
-
