SlideShare ist ein Scribd-Unternehmen logo
1 von 51
PHPUnit + Xdebug单元测试技术 ——提升编码质量的工具和方法
讨论的主题 PHPUnit单元测试技术 Xdebug调试
声明 这仅是一个宣传、引导 会写测试并提升了 工作质量、减少返工次数 的程序员,牧师 老大说了,会更容易得到管理层的奖励和青睐
如何测试… 测试基础
一个例子: Stack.php <?php classStack { private $store; publicfunction__construct() {                   $this->store = array();         } publicfunctionpush($o) { array_push($this->store, $o);         } publicfunctionpop() { returnarray_pop($this->store);         } publicfunctioncount() { returncount($this->store);         } }
如何保证正确性? 手眼测试… 在程序底部添加一些测试语句 $stack = new Stack; if ($stack) { echo $stack->count();     $stack->push(1111); echo $stack->count(); echo $stack->pop(); echo $stack->count(); }
测试成功后… 剔除/注释 掉这些语句…
下一次再修改时… 重新加上这些测试语句, 并再次测试 回归测试
问题是… 每次修改都要重新加上这些测试, 以验证没有(未预期地) 破坏原有功能… 好吧, 为何不把测试独立出来呢?
好主意!! 把测试独立成一个文件, 每次执行一下即可 无需再做 剔除/注释 – 加上/反注释 工作了 StackTest.php ------------------------------------------------------------------------------------------- <?php require_once ‘./Stack.php’; $stack = new Stack; if ($stack) { echo $stack->count();     $stack->push(1111); echo $stack->count(); echo $stack->pop(); echo $stack->count(); }
新问题是… 每次都要 手眼测试, 太累了!!! 呣, 有没有办法让 机器 去做? 然后自己就有时间去 把妹子…
PHPUnit来帮忙 <?php require_once'./Stack.php'; class StackTestextends PHPUnit_Framework_TestCase { public function testCanPushAndPop() {         $stack = new Stack();         $this->assertEquals(0, $stack->count());         $stack->push('foo');         $this->assertEquals(1, $stack->count());         $this->assertEquals('foo', $stack->pop());         $this->assertEquals(0, $stack->count());     } }
执行测试 $ phpunitStackTest
执行测试 成功时:
执行测试 失败时:
- 互动演示 -
Stack 增加新功能时… <?php classStack { private $store; publicfunction__construct() {                   $this->store = array();         } publicfunctionpush($o) { array_push($this->store, $o);         } publicfunctionpop() { returnarray_pop($this->store);         } publicfunctioncount() { returncount($this->store);         } public function clean() {                  $this->store = array();         } }
<?php require_once'./Stack.php'; class StackTestextends PHPUnit_Framework_TestCase { public function testCanPushAndPop() {         $stack = new Stack();         $this->assertEquals(0, $stack->count());         $stack->push('foo');         $this->assertEquals(1, $stack->count());         $this->assertEquals('foo', $stack->pop());         $this->assertEquals(0, $stack->count());     }     public function testCanClean() {         $stack = new Stack();         $stack->push('foo');         $this->assertEquals(1, $stack->count());         $stack->clean();         $this->assertEquals(0, $stack->count());     } } 也要增加新测试…
- 互动演示 -
xUnit方法的优势 减少验证 ‘代码正确性’ 的工作量 自动化回归测试 避免系统退步 写测试用例可以促使程序员发现边界条件 测试用例本身就是很好的示范代码和文档 写测试用例可以促使程序员真正了解需求 完备的测试可以给程序员以信心 More…
什么是测试? 测试是一组输入、执行条件以及预期结果的集合 一组断言 测试是一个产品的详细接口规格 如何调用,结果值会是如何,etc. 测试定义产品的每一个面 测试是… 这一页 PPT 本身就是个测试…
鸭子 “When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.” James Whitcomb Riley (1849 – 1916) (Duck typing)
人 “人就是以为自己不是机器的机器” Wang Wenlin (1981 – ∞) 以为自己不是机器的机器, 是人…
框架中的测试 Zend Framework & Symfony 1
良好的测试支持 Zend Framework 集成 PHPUnit支持 Symfony 1 使用自己的 Lime 测试框架 Symfony 2 已改用 PHPUnit … 它们都能自动生成 功能测试 骨架…
Zend Framework 示例 $ zf create project demo $ zf create controller foo $ phpunit
Zend Framework 示例 <?php classIndexControllerTestextendsZend_Test_PHPUnit_ControllerTestCase {     … publicfunctiontestIndexAction()     {         $params = array('action' => 'index', 'controller' => 'Index', 'module' => 'default');         $urlParams = $this->urlizeOptions($params);         $url = $this->url($urlParams);         $this->dispatch($url);         // assertions         $this->assertModule($urlParams['module']);         $this->assertController($urlParams['controller']);         $this->assertAction($urlParams['action']);         $this->assertQueryContentContains("div#welcome h3", "This is your project's main page");     } }
- 互动演示 -
Symfony示例 $ symfonygenerate:project demo $ symfonygenerate:appfoo $ symfonygenerate:modulefoo bar $ symfonytest:all $ symfonytest:functionalfoo
Symfony示例 <?php include(dirname(__FILE__).'/../../bootstrap/functional.php'); $browser = newsfTestFunctional(new sfBrowser()); $browser-> get('/content/index')-> with('request')->begin()-> isParameter('module', 'content')-> isParameter('action', 'index')-> end()-> with('response')->begin()-> isStatusCode(200)-> checkElement('body', '!/This is a temporary page/')-> end() ;
- 互动演示 -
好消息… 功能测试脚本, 测试组会帮忙制作… 程序员只需做单元测试
PHPUnit还能做什么…
代码覆盖报告 $ phpunit --coverage-html covStackTest 代码覆盖报告,一种调试工具。
- 互动演示 -
生成规格文档 $ phpunit --testdoxStackTest 测试 即是 定义。
生成规格文档
- 互动演示 -
测试失败时… Xdebug来帮忙
Xdebug出场… 简便的 PHP 调试、跟踪 和 剖析 工具 我们主要用它的 远程调试功能
如何调试一个测试? $ export XDEBUG_CONFIG="remote_host=192.168.8.91idekey=netbeans-xdebug" ## plain old php $ phpunitStackTest ## zend framework $ phpunit application/controllers/FooControllerTest ## symfony 1 $ symfonytest:functionalfoo
断点 单步 上下文
- 互动演示 -
Xdebug的其它能力… 跟踪 (Trace) 性能剖析 (Profile)
一点疑惑
断言… 可以吗? 这种定义事物的方式可能并不充分 但至少是必要的 可是仍然是不够充分… 世界上从来没有 ‘完全充分’,就像合同不够充分,法律不会完美一样 我们的目标是测试案例能覆盖到所有的代码路径即可
测试不是测试组的事吗? 单元测试 习惯上、实践上 是 程序员写的 只有程序员自己知道怎么测… 而且,它也是一种调试工具 功能测试 习惯上 是 测试组 来做 但仍然需要程序员的紧密配合
最后…
…谢谢!!

Weitere ähnliche Inhalte

Was ist angesagt?

Maintainable PHP Source Code
Maintainable PHP Source CodeMaintainable PHP Source Code
Maintainable PHP Source CodeBo-Yi Wu
 
LazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLin Yo-An
 
5, initialization & cleanup
5, initialization & cleanup5, initialization & cleanup
5, initialization & cleanupted-xu
 
.Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發).Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發)Gelis Wu
 
那些年,我們一起看的例外
那些年,我們一起看的例外那些年,我們一起看的例外
那些年,我們一起看的例外kao kuo-tung
 
Javascript Training
Javascript TrainingJavascript Training
Javascript Trainingbeijing.josh
 
JavaScript现代化排错实践
JavaScript现代化排错实践JavaScript现代化排错实践
JavaScript现代化排错实践jeffz
 
Bash shell script 教學
Bash shell script 教學Bash shell script 教學
Bash shell script 教學Ming-Sian Lin
 
JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1Sheng-Han Su
 
Python 入门
Python 入门Python 入门
Python 入门kuco945
 
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學Bo-Yi Wu
 
基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程zhangdaiping
 
Ptyhon 教學 001 程式流程控制(if-elif-else)
Ptyhon 教學 001 程式流程控制(if-elif-else)Ptyhon 教學 001 程式流程控制(if-elif-else)
Ptyhon 教學 001 程式流程控制(if-elif-else)信宏 陳
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
Hello Javascript
Hello JavascriptHello Javascript
Hello JavascriptBaidu, Inc.
 
PHPUnit Myth
PHPUnit MythPHPUnit Myth
PHPUnit Mythjameslabs
 
Introduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDKIntroduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDK維佋 唐
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训lotusprince
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错jeffz
 

Was ist angesagt? (20)

Maintainable PHP Source Code
Maintainable PHP Source CodeMaintainable PHP Source Code
Maintainable PHP Source Code
 
LazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHP
 
5, initialization & cleanup
5, initialization & cleanup5, initialization & cleanup
5, initialization & cleanup
 
.Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發).Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發)
 
那些年,我們一起看的例外
那些年,我們一起看的例外那些年,我們一起看的例外
那些年,我們一起看的例外
 
Javascript Training
Javascript TrainingJavascript Training
Javascript Training
 
JavaScript现代化排错实践
JavaScript现代化排错实践JavaScript现代化排错实践
JavaScript现代化排错实践
 
Node way
Node wayNode way
Node way
 
Bash shell script 教學
Bash shell script 教學Bash shell script 教學
Bash shell script 教學
 
JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1
 
Python 入门
Python 入门Python 入门
Python 入门
 
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學
 
基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程
 
Ptyhon 教學 001 程式流程控制(if-elif-else)
Ptyhon 教學 001 程式流程控制(if-elif-else)Ptyhon 教學 001 程式流程控制(if-elif-else)
Ptyhon 教學 001 程式流程控制(if-elif-else)
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
Hello Javascript
Hello JavascriptHello Javascript
Hello Javascript
 
PHPUnit Myth
PHPUnit MythPHPUnit Myth
PHPUnit Myth
 
Introduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDKIntroduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDK
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错
 

Andere mochten auch

常见编程问题及对策
常见编程问题及对策常见编程问题及对策
常见编程问题及对策hoopchina
 
虎扑基础设施架构探讨
虎扑基础设施架构探讨虎扑基础设施架构探讨
虎扑基础设施架构探讨hoopchina
 
Doctrine Migration
Doctrine MigrationDoctrine Migration
Doctrine Migrationhoopchina
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnitvaruntaliyan
 
Lightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika Aldaba
Lightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika AldabaLightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika Aldaba
Lightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika Aldabaux singapore
 
SEO: Getting Personal
SEO: Getting PersonalSEO: Getting Personal
SEO: Getting PersonalKirsty Hulse
 

Andere mochten auch (7)

常见编程问题及对策
常见编程问题及对策常见编程问题及对策
常见编程问题及对策
 
虎扑基础设施架构探讨
虎扑基础设施架构探讨虎扑基础设施架构探讨
虎扑基础设施架构探讨
 
Doctrine Migration
Doctrine MigrationDoctrine Migration
Doctrine Migration
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnit
 
Lightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika Aldaba
Lightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika AldabaLightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika Aldaba
Lightning Talk #9: How UX and Data Storytelling Can Shape Policy by Mika Aldaba
 
SEO: Getting Personal
SEO: Getting PersonalSEO: Getting Personal
SEO: Getting Personal
 
Succession “Losers”: What Happens to Executives Passed Over for the CEO Job?
Succession “Losers”: What Happens to Executives Passed Over for the CEO Job? Succession “Losers”: What Happens to Executives Passed Over for the CEO Job?
Succession “Losers”: What Happens to Executives Passed Over for the CEO Job?
 

Ähnlich wie PHPUnit + Xdebug 单元测试技术

Phpunit入门 r2
Phpunit入门 r2Phpunit入门 r2
Phpunit入门 r2Baohua Cai
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型keelii
 
GTest交流与经验总结
GTest交流与经验总结GTest交流与经验总结
GTest交流与经验总结coderzh
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)RANK LIU
 
學好 node.js 不可不知的事
學好 node.js 不可不知的事學好 node.js 不可不知的事
學好 node.js 不可不知的事Ben Lue
 
Coding guideline
Coding guidelineCoding guideline
Coding guideline斯理 衛
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學Sita Liu
 
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会Zhi Zhong
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsHo Kim
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoloadjay li
 
由一个简单的程序谈起--之四
由一个简单的程序谈起--之四由一个简单的程序谈起--之四
由一个简单的程序谈起--之四yiditushe
 
Keep your code clean
Keep your code cleanKeep your code clean
Keep your code cleanmacrochen
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
Slide 20120322
Slide 20120322Slide 20120322
Slide 20120322Yubei Li
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层yiditushe
 
J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识yiditushe
 

Ähnlich wie PHPUnit + Xdebug 单元测试技术 (20)

Phpunit入门 r2
Phpunit入门 r2Phpunit入门 r2
Phpunit入门 r2
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
 
Sun java
Sun javaSun java
Sun java
 
GTest交流与经验总结
GTest交流与经验总结GTest交流与经验总结
GTest交流与经验总结
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)
 
學好 node.js 不可不知的事
學好 node.js 不可不知的事學好 node.js 不可不知的事
學好 node.js 不可不知的事
 
PHP
PHPPHP
PHP
 
Coding guideline
Coding guidelineCoding guideline
Coding guideline
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學
 
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming Skills
 
Hi Haskell
Hi HaskellHi Haskell
Hi Haskell
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
 
由一个简单的程序谈起--之四
由一个简单的程序谈起--之四由一个简单的程序谈起--之四
由一个简单的程序谈起--之四
 
Keep your code clean
Keep your code cleanKeep your code clean
Keep your code clean
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
Slide 20120322
Slide 20120322Slide 20120322
Slide 20120322
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层
 
Optimzing mysql
Optimzing mysqlOptimzing mysql
Optimzing mysql
 
J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识
 

Kürzlich hochgeladen

哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制jakepaige317
 
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxEDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxmekosin001123
 
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...黑客 接单【TG/微信qoqoqdqd】
 
educ6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxeduc6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxmekosin001123
 
EDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxEDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxmekosin001123
 
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书jakepaige317
 

Kürzlich hochgeladen (6)

哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
 
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxEDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
 
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
 
educ6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxeduc6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptx
 
EDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxEDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptx
 
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
 

PHPUnit + Xdebug 单元测试技术