当前位置:小鱼儿玄机二站 > 计算机网络 > Yaf框架与PHPUnit的集成测试,PHPUNIT深入用法

Yaf框架与PHPUnit的集成测试,PHPUNIT深入用法

文章作者:计算机网络 上传时间:2019-10-03

Yaf,全称 Yet Another Framework,是一个C语言编写的PHP框架。自从接触Yaf以来也快1年了,Yaf的性能确实非常不错,但是相应的资料比较少。一直想把PHPUnit使用在Yaf上,网上搜了一圈这方面的资料非常非常少。于是自己折腾了下这个,初步处理了一下关于控制器(controller)和模型(model)的测试。

在本文中,笔者将为大家介绍phpunit中的两个高级概念和用法,尽管它不一定在你的日常单元测试中都用到,但理解和学会它们的用法对学习phpunit还是十分重要的。

代码可以直接在github下载:https://github.com/chenjiebin/yaf-phpunit-test/

  Phpunit中的Annotations

先报下运行环境:

  如果有其他编程语言经验的开发者,应该对Annotations(注解)不陌生,其实在phpunit中,一个简单的如下面的一段注释也可以认为是Annotations:

PHP:5.3.13或者5.4.16
Yaf:2.2.9
phpunit:3.7.29在php 5.3.13和5.4.16下都没有发现问题,Yaf扩展要注意下载相应的版本。

图片 1<?php
图片 2class MyTestClass extends PHPUnit_Framework_TestCase
图片 3{
图片 4/**
图片 5* Testing the answer to “do you love unit tests?”
图片 6*/
图片 7public function testDoYouLoveUnitTests()
图片 8{
图片 9$love = true;
图片 10$this->assertTrue($love);
图片 11}
图片 12}
图片 13?>

下面说明下相关文件和代码。

   可以看到,其实一段以/** **/为标记的文字,就可以认为是一种Annotations,但Annotations其实不单单是简单的注释,它是与一个程序元素相关联信息或者元数据的标注,它不影响程序的运行,但相关的软件工具或框架能够将其转换成特殊的元数据标记,以方便开发者以更少的代码去提高效率(比如通过。如果你熟悉Java,则会发现在Java SE 5中及象Spring等框架中,都大量使用了Annotations。

测试目录为tests。

  然而,由于php并不象Java那样是编译性语言,因此本身缺乏去解析Annotations的机制,但幸好phpunit去提供了这样的功能,我们以下面的代码为例:

phpunit.xml文件

图片 14<?php
图片 15class MyMathClass
图片 16{
图片 17/**
图片 18* Add two given values together and return sum
图片 19*/
图片 20public function addValues($a,$b)
图片 21{
图片 22return $a+$b;
图片 23}
图片 24}
图片 25?>

PHPUnit配置文件,内容如下:

   上面的只是一个简单的加法的例子,为此,我们使用Annotations去编写一个单元测试,在上两篇文章中,我们采用的是手工编写单元测试的方法,而本文中,将介绍使用phpunit命令行的方法,自动生成单元测试的框架,方法如下:

 <phpunit bootstrap="./bootstrap.php"></phpunit>

  首先把上面的类保存为MyMathClass.php,然后在命令行下运行如下命令:

表示测试执行时从bootstrap.php开始引导。

图片 26phpunit –skeleton-test MyMathClass

bootstrap.php文件

   这时phpunit会自动生成如下的框架单元测试代码:

测试执行的引导文件,声明常量等一些全局配置都可以在这里做。内容如下:

图片 27<?php
图片 28require_once '/path/to/MyMathClass.php';
图片 29/**
图片 30* Test class for MyMathClass.
图片 31* Generated by PHPUnit on 2011-02-07 at 12:22:07.
图片 32*/
图片 33class MyMathClassTest extends PHPUnit_Framework_TestCase
图片 34{
图片 35/**
图片 36* @var MyMathClass
图片 37*/
图片 38protected $object;
图片 39/**
图片 40* Sets up the fixture, for example, opens a network connection.
图片 41* This method is called before a test is executed.
图片 42*/
图片 43protected function setUp()
图片 44{
图片 45$this->object = new MyMathClass;
图片 46}
图片 47/**
图片 48* Tears down the fixture, for example, closes a network connection.
图片 49* This method is called after a test is executed.
图片 50*/
图片 51protected function tearDown()
图片 52{
图片 53}
图片 54/**
图片 55* @todo Implement testAddValues().
图片 56*/
图片 57public function testAddValues()
图片 58{
图片 59// Remove the following lines when you implement this test.
图片 60$this->markTestIncomplete(
图片 61'This test has not been implemented yet.'
图片 62);
图片 63}
图片 64}
图片 65?>
图片 66

 define("APPLICATION_PATH", realpath(dirname(__FILE__) . '/../'));

   可以看到,phpunit为我们生成的单元测试代码自动引入了原来的MyMathClass.php,同时也生成了setUp和tearDown方法,但唯一的核心单元测试代码是留给了我们编写。如果想在这个基础上更快速的生成我们想要的单元测试代码,要如何实现呢?没错,就是使用annotations!我们可以在原来的MyMathClass.php中加入如下的annotations。

applicationlibraryTestPHPUnitTestCase.php文件
自定义的测试基类文件,控制器和模型的测试类都继承该类。代码如下:

图片 67<?php
图片 68class MyMathClass
图片 69{
图片 70/**
图片 71* Add two given values together and return sum
图片 72* @assert (1,2) == 3
图片 73*/
图片 74public function addValues($a,$b)
图片 75{
图片 76return $a+$b;
图片 77}
图片 78}
图片 79?>
图片 80

 代码如下

  然后再象上述一样在命令行运行:

namespace TestPHPUnit;
/**
 * 测试基类
 */
class TestCase extends PHPUnit_Framework_TestCase {
    /**
     * yaf运行实例
     *
     * @var YafApplication
     */
    protected $_application = null;
    /**
     * 构造方法,初始化yaf运行实例
     */
    public function __construct() {
        $this->_application = $this->getApplication();
        parent::__construct();
    }
    /**
     * 设置application
     */
    public function setApplication() {
        $application = new YafApplication(APPLICATION_PATH . "/conf/application.ini");
        $application->bootstrap();
        YafRegistry::set('application', $application);
    }
    /**
     * 获取application www.111cn.net
     *
     * @return YafApplication
     */
    public function getApplication() {
        $application = YafRegistry::get('application');
        if (!$application) {
            $this->setApplication();
        }
        return YafRegistry::get('application');
    }
}

图片 81  phpunit –skeleton-test MyMathClass

因为Yaf在运行的时候,全局只能实例化一次,所以在初始化Yaf运行实例后,就保存到Yaf的注册表里避免多次实例化。此外在构造方法里就调用初始化Yaf运行实例的方法,是为了在数据模型的测试中,可以直接new出相应的数据模型,而不用导入相关的文件。

  这个时候会为我们生成如下的单元测试代码:

applicationlibraryTestPHPUnitControllerTestCase.php文件

图片 82<?php
图片 83/**
图片 84* Generated from @assert (1,2) == 3.
图片 85*/
图片 86public function testAddValues()
图片 87{
图片 88$this->assertEquals(
图片 893,
图片 90$this->object->addValues(1,2)
图片 91);
图片 92}
图片 93?>
图片 94

控制器测试基类,控制器的测试类都继承该类。内容如下:

  看到了么?我们在原有的类中加入了注解@assert(1,2)==3,则phpunit自动为我们生成了正确的单元测试代码。当然,可以参考phpunit手册,学习到更多的关于@assert注解使用的规则。

 代码如下

  下面再举一个例子来讲解annotations。假设我们的程序中的一个方法,只是仅需要数据的输入,并且不依赖XML或者数据库提供数据源,则为了测试这个方法,我们可能想到的一个方法是在程序中设置一个测试数据集去测试,但这里介绍一个比较简单的方法,就是使用注解@dataProvider,修改MyMathClass.php如下:

namespace TestPHPUnit;
require_once APPLICATION_PATH . '/tests/application/library/Test/PHPUnit/TestCase.php';
/**
 * 控制器测试基类
 */
class ControllerTestCase extends TestPHPUnitTestCase {
  
}

图片 95<?php
图片 96/**
图片 97* Data provider for test methods below
图片 98*/
图片 99public static function provider()
图片 100{
图片 101return array(
图片 102array(1,2,3),
图片 103array(4,2,6),
图片 104array(1,5,7)
图片 105);
图片 106}
图片 107/**
图片 108* Testing addValues returns sum of two values
图片 109* @dataProvider provider
图片 110*/
图片 111public function testAddValues($a,$b,$sum)
图片 112{
图片 113$this->assertEquals(
图片 114$sum,
图片 115$this->object->addValues($a,$b)
图片 116);
图片 117}
图片 118?>
图片 119

暂时没有代码,为将来扩展预留。

   可以看到,这里使用了注解@dataProvider,指明了测试用例的数据提供者是由provider方法返回的一个数组。所以在单元测试时,数组中的第0个元素则会赋值给$a,第1个元素则会赋值给b,第3个元素则会赋值给sum,可以看到,上面的第3个数组提供的数据是不能通过单元测试的,因为1+5不等于7。

applicationlibraryTestPHPUnitModelTestCase.php文件

  此外,这里还简单介绍两个常用的annotations,比如@expectedException注解可以测试代码中是否正确抛出了异常,比如:

模型测试基类,模型的测试类都继承该类。内容如下:

图片 120<?phprequire_once 'PHPUnit/Framework.php';
图片 121class ExceptionTest extends PHPUnit_Framework_TestCase{    
图片 122/**  
图片 123   * @expectedException InvalidArgumentException     */    
图片 124public function testException()    {  
图片 125  }
图片 126}
图片 127
图片 128?>
图片 129

 代码如下

   这里就用注解的方法表示testException中必须抛出的异常类型为InvalidArgumentException。

namespace TestPHPUnit;
require_once APPLICATION_PATH . '/tests/application/library/Test/PHPUnit/TestCase.php';
/**
 * 数据模型测试基类
 */
class ModelTestCase extends TestPHPUnitTestCase {
  
}

  另外一个是@cover注解。它的作用是标识phpunit只为类中的哪些方法或作用域生成测试代码,比如:

applicationcontrollersIndexTest.php首页控制器测试文件

图片 130/**
图片 131     * @covers SampleClass::publicMethod
图片 132     * @covers SampleClass::<!public>
图片 133     * @covers HelperClass<extended>
图片 134     */
图片 135    public function testMethod()
图片 136    {
图片 137        $result = SampleClass::method();
图片 138}
图片 139

控制器测试示例文件,内容如下:

   则phpunit只为SampleClass类中的publicMethod方法、SampleClass类中的所有非public声明的方法和HelperClass类或者它的其中一个父类产生单元测试代码。

 代码如下

12下一页阅读全文

require_once APPLICATION_PATH . '/tests/application/library/Test/PHPUnit/ControllerTestCase.php';
/**
 * 首页控制器测试类
 */
class IndexTest extends TestPHPUnitControllerTestCase {
    /**
     * 测试index方法
     */
    public function testIndex() {
        $request = new YafRequestSimple("CLI", "Index", "Index", 'index');
        $response = $this->_application->getDispatcher()
                ->returnResponse(true)
                ->dispatch($request);
        $content = $response->getBody();
        $this->assertEquals('index phtml', $content);
    }
}

您可能感兴趣的文章:

  • Windows下安装PHP单元测试环境PHPUnit图文教程
  • PHP单元测试利器 PHPUNIT初探
  • PHP单元测试利器 PHPUNIT深入用法(二)
  • php单元测试phpunit入门实例教程
  • laravel单元测试之phpUnit中old()函数报错解决
  • Windows下wamp php单元测试工具PHPUnit安装及生成日志文件配置方法
  • PHP单元测试PHPUnit简单用法示例
  • ThinkPHP分组下自定义标签库实例
  • ThinkPHP使用Smarty第三方插件方法小结
  • thinkPHP框架单元测试库tpunit用法示例

测试控制器主要是使用YafRequestSimple类,设定参数为CLI则为命令行运行。

applicationcontrollersmodelsUserTest.php模型测试文件

数据模型测试文件,内容如下:

 代码如下

require_once APPLICATION_PATH . '/tests/application/library/Test/PHPUnit/ModelTestCase.php';
class UserTest extends TestPHPUnitModelTestCase {
    public function testGetUserName() {
        $model = new UserModel();
        $userId = 1;
        $result = $model->getUserName($userId);
        $this->assertEquals('iceup', $result);

        $userId = 100;
        $result = $model->getUserName($userId);
        $this->assertFalse($result);
    }
}

这里可以直接new UserModel()出来,因为在测试基类的构造方法里已经初始化了Yaf运行实例。

小结

执行测试的时候一般最头疼的是文件的自动加载问题,基本上只要解决了这个问题,剩下都比较容易处理了。目前在项目的运用中碰到一些实际的问题,比如输出json格式的数据,抛出异常,post传参等,以后会陆续补上相应的解决方式。

本文由小鱼儿玄机二站发布于计算机网络,转载请注明出处:Yaf框架与PHPUnit的集成测试,PHPUNIT深入用法

关键词: