php单元测试使用示例(转载) 博客分类: PHP php单元测试
程序员文章站
2024-02-16 15:15:10
...
转载自:http://www.javaranch.com/unit-testing.jsp,原文标题《Evil Unit Testing》,原作者:Paul Wheaton
转载自: http://www.cnblogs.com/harlanc/p/6838155.html ,原文标题《单元测试有毒》翻译者:HarlanC
我稍做了修改。
作者的核心观点是:绝大部分的项目,应该做的测试是,单元测试70%,其余才是功能测试和集成测试。单元测试是基础。
作者的观点:
单元测试是可测试代码的最小的一部分。通常是一个单一的方法,不会使用其它方法或者类。非常快!上千个单元测试能够在10秒以内跑完!单元测试永远不会使用:
单元测试几乎总是回归测试套件(regression suite)的一部分。
下面是单元测试使用示例:
假设被测类FarmServlet如下:
这里不仅仅调用了其他业务逻辑,还调用了应用服务器!可能还会访问网络!上千次的调用可能会花费不少于10秒的时间。另外对$remote的修改可能会破坏我对这个方法的测试!所以我们需要引入一个mock对象。
首先是创建mock。如果$remote是一个对象,我将会继承(extend)它并且重写(override)或实现(implement)所有的方法。
这个MockRemote类什么都没做,只是携带了单元测试和需要被测试代码之间要交互的数据。
现在我需要使用mock代码来替代调用应用服务器的部分。我对需要使用mock的地方做了注释:
首先,被测类FarmServlet中,让我们把这句代码从其他猛兽中分离出来:
前面已经新写了一个mock类,现在再写一个类FarmServletShunt继承被测类,然后对继承的这个类做测试,成功即认为原先的被测类功能正确。
注意一下怪异的名字:“shunt”。我不确定它是什么意思,但我认为这个词语来自电子工程/工艺,它指用一段电线来临时组装一个完整的电路。一开始听起来这个想法很愚蠢,但是过后我就慢慢习惯了。
一个shunt有点像mock,一个没有重写所有方法的mock。用这种方法,你可以mock一些方法,然后测试其他的方法。一个单元测试可以由几个shunts来完成,它们重写了相同的类,每个shunt测试了类的不同部分。Shunt通常情况下为嵌套类。
再对ServletData做mock,方便注入。
终场表演的时候到了!看一下单元测试代码!
基本的测试框架我们就展示完了。下面我要和大家分享一个和单元测试有关的概念——依赖注入,也是我们的单元测试中要到的,敬请期待。
转载自: http://www.cnblogs.com/harlanc/p/6838155.html ,原文标题《单元测试有毒》翻译者:HarlanC
我稍做了修改。
作者的核心观点是:绝大部分的项目,应该做的测试是,单元测试70%,其余才是功能测试和集成测试。单元测试是基础。
作者的观点:
单元测试是可测试代码的最小的一部分。通常是一个单一的方法,不会使用其它方法或者类。非常快!上千个单元测试能够在10秒以内跑完!单元测试永远不会使用:
- 数据库
- 一个app服务器(或者任何类型的服务器)
- 文件/网络 I/O或者文件系统
- 另外的应用
- 控制台(System.out,system.err等等)
- 日志
- 大多数其他类(但不包括DTO‘s,String,Integer,mock和一些其他的类)
单元测试几乎总是回归测试套件(regression suite)的一部分。
下面是单元测试使用示例:
假设被测类FarmServlet如下:
//原被测类 public class FarmServlet extends ActionServlet { public function doAction( ServletData $servletData ) { $species = $servletData->getParameter("species"); $buildingID = $servletData->getParameter("buildingID"); if ( Str::usable( $species ) && Str::usable( $buildingID ) ) { $remote = FarmEJBUtil::getHome()->create(); $remote->addAnimal( $species , $buildingID ); } } }
这里不仅仅调用了其他业务逻辑,还调用了应用服务器!可能还会访问网络!上千次的调用可能会花费不少于10秒的时间。另外对$remote的修改可能会破坏我对这个方法的测试!所以我们需要引入一个mock对象。
首先是创建mock。如果$remote是一个对象,我将会继承(extend)它并且重写(override)或实现(implement)所有的方法。
//远程服务对象mock类, //新写的第一个类,为了单元测试 public class MockRemote { $addAnimal_species = null; $addAnimal_buildingID = null; $addAnimal_calls = 0; public function addAnimal( $species, $buildingID ) { $this->addAnimal_species = $species ; $this->addAnimal_buildingID = $buildingID ; $this->addAnimal_calls++; } }
这个MockRemote类什么都没做,只是携带了单元测试和需要被测试代码之间要交互的数据。
现在我需要使用mock代码来替代调用应用服务器的部分。我对需要使用mock的地方做了注释:
首先,被测类FarmServlet中,让我们把这句代码从其他猛兽中分离出来:
//修改后的原被测类,为了单元测试,以及代码解耦。 public class FarmServlet extends ActionServlet { // 新加公共的成员方法,可以让测试类注入或通过继承修改。 public function getRemote() { return FarmEJBUtil::getHome()->create(); } public function doAction( ServletData $servletData ) { $species = $servletData->getParameter("species"); $buildingID = $servletData->getParameter("buildingID"); if ( Str::usable( $species ) && Str::usable( $buildingID ) ) { $remote = $this->getRomote(); // 改成从公共成员方法中获取对象 $remote->addAnimal( $species , $buildingID ); } } }
前面已经新写了一个mock类,现在再写一个类FarmServletShunt继承被测类,然后对继承的这个类做测试,成功即认为原先的被测类功能正确。
//该类FarmServletShunt继承被测类,测试用 // 新写的第2个类 class FarmServletShunt extends FarmServlet { puhblic $getRemote_return; // 新加成员变量,好注入 public function getRemote() // 覆盖了被测类的获得远程服务的方法,实现注入 { return getRemote_return; } }
注意一下怪异的名字:“shunt”。我不确定它是什么意思,但我认为这个词语来自电子工程/工艺,它指用一段电线来临时组装一个完整的电路。一开始听起来这个想法很愚蠢,但是过后我就慢慢习惯了。
一个shunt有点像mock,一个没有重写所有方法的mock。用这种方法,你可以mock一些方法,然后测试其他的方法。一个单元测试可以由几个shunts来完成,它们重写了相同的类,每个shunt测试了类的不同部分。Shunt通常情况下为嵌套类。
再对ServletData做mock,方便注入。
//对ServletData类或接口做mock //新写的第3个类,为了单元测试 public class MockServletData { private $arr; public function __construct($arr){ $this->arr = $arr; } public function getParameter( $parameter ) { return $this->arr[$paramter]; } }
终场表演的时候到了!看一下单元测试代码!
// 这是最后写的测试文件, public class TestFarmServlet extends TestCase { public function testAddAnimal() { $mockRemote = new MockRemote();//定义mock的远程服务对象 $shunt = new FarmServletShunt();//该类继承被测类,拿它测试 $shunt->getRemote_return = $mockRemote; //注入远程服务对象 // 另一个mock对象 $mockServletData = new MockServletData([ // 定义mock的ServletData对象 "species" => "dog", "buildingID" => 27, ]); // 执行被测方法 $shunt->doAction( $mockServletData ); // 断言原被测类中,远程对象使用了一次addAnimal方法 $this->assertEquals( 1 , $mockRemote->addAnimal_calls ); //个人感觉下面两句不重要。因为这里的逻辑其实是mock里的逻辑。 $this->assertEquals( "dog" , $mockRemote->addAnimal_species ); $this->assertEquals( 27 , $mockRemote->addAnimal_buildingID ); } }
基本的测试框架我们就展示完了。下面我要和大家分享一个和单元测试有关的概念——依赖注入,也是我们的单元测试中要到的,敬请期待。
推荐阅读
-
php单元测试使用示例(转载) 博客分类: PHP php单元测试
-
php测试框架概览 博客分类: PHP php单元测试prophecy
-
php单元测试进阶(2)-入门 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(3)- 入门 - 添加检验 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(9)- 核心技术 - 桩件(stub) - 工厂类注入桩件 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(8)- 核心技术 - 桩件(stub) - 属性注入桩件 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(6)- 核心技术 - 桩件(stub) 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(7)- 核心技术 - 桩件(stub) - 构造函数注入桩件 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(4)- 入门 - 使用参数化测试 博客分类: PHP phpunit单元测试php单元测试进阶
-
php单元测试进阶(12)- 核心技术 - mock对象 博客分类: PHP phpunit单元测试php单元测试进阶