CakePHP的测试方法

CakePHP的测试方法

CakePHP 测试的文档

注意

  1. PHPUnit 4 与 CakePHP 的单元测试不兼容
  2. 在 app/Config/core.php 文件中的调试(debug)级别至少是 1。当调试级别是 0 时,无法通过 web 运行器访问测试。在运行任何测试之前,应当确保 添加 $test 数据库配置。该配置被 CakePHP 用于测试夹具(fixture)的表和数据
  3. 当使用 PHPUnit 3.6+ 时,所有的输出都会被吞没。如果使用 CLI,可以添加 --debug 修饰符;如果使用 web 运行器来显示输出,可以添加 &debug=1 到网址中
  4. 在命令行运行使用会话的测试时,需要加上 --stderr 标志。不这么做会导致会话无法 工作。PHPUnit 默认会输出测试进程到标准输出(stdout),这会使 PHP 以为头部信息 已经发送,从而阻止会话启动。把 PHPUnit 输出切换到 stderr,就避免了这个问题

步骤

  1. 安装PHPUnit
    使用composer安装方法,"phpunit/phpunit": "3.7.32"
  2. (可选)测试数据库的设置,在database.php中添加$test变量
  3. webroot目录有test.php的前提下,可以直接访问localhost/appname/webroot/test.php,如有配置虚拟域名,可能是xx.com/test.php
  4. 测试用例存放目录在/Test/Case中,文件名有要求:必须以Test.php结尾,如UserTest.php,含有测试的类应当扩展 CakeTestCase,ControllerTestCase 或 PHPUnit_Framework_TestCase,所以类名(与文件名对应)示例class UserTest extends CakeTestCase,方法名要求是以test开头,如public function testPublished()
  5. 可以使用web访问的方式测试,也可以用命令行,./Console/cake test app Model/Post,这里的cake命令是在Console目录下的,与执行shell脚本的命令一样,test和app两个参数不需要改变,Model/Post指向的是/Test/Case/Model/PostTest.php
  6. 以下一则测试的例子:
        Article = ClassRegistry::init('Article');
                }
    
                public function testA() {
                    $this->assertEquals(1, 1);
                }
    
                public function testB() {
                    $ads = $this->Ad->getRunningAds();
                    var_dump($ads);
                    $this->assertEquals($ads[4397]['banner'][0]['axid'], 4397);
                }
    
                public function testC() {
                    $ads = $this->Ad->getRunningAds();
                    var_dump($ads);
                    $this->assertEquals($ads[4397]['banner'][0]['axid'], 4398);
                }
            }
            /*
                测试用例有一些生命周期回调函数,可以在测试时使用:
    
                setUp 在每个测试方法之前调用。应当用来创建要测试的对象,为测试初始化任何 数据。记得一定要调用 parent::setUp()。
                tearDown 在每个测试方法之后调用。应当用来在测试完成之后进行清理。记得一定 要调用 parent::tearDown()。
                setupBeforeClass 在一个用例中的测试方法开始之前只调用一次。该方法必须是 静态的。
                tearDownAfterClass 在一个用例中的测试方法完成之后只调用一次。该方法必须是 静态的。
            */
    
  7. 覆盖率检测:使用xdebug工具,PHPUnit会结合工具检测出测试代码的盲区(无关代码不会影响覆盖率的计算,如测试的是方法A,在运行的过程中没有经过方法B,并不会影响覆盖率;但是方法A中的if语句,只走了其中一个条件,则会提示未覆盖)
    xdebug安装方法
    php-xdebug扩展:composer安装方法"ext-xdebug": ">=2.0.5"

测试模型

    App::uses('Article', 'Model');

    class ArticleTest extends CakeTestCase {
        public $fixtures = array('app.article');

        public function setUp() {
            parent::setUp();
            // 在为测试设置模型时,使用 ClassRegistry::init('YourModelName')的原因是它知道要使用测试数据库连接(如果不使用测试数据库和夹具,直接new也可以)
            $this->Article = ClassRegistry::init('Article');
        }

        public function testPublished() {
            // Article模型中有一个published方法
            $result = $this->Article->published(array('id', 'title'));
            $expected = array(
                array('Article' => array('id' => 1, 'title' => 'First Article')),
                array('Article' => array('id' => 2, 'title' => 'Second Article')),
                array('Article' => array('id' => 3, 'title' => 'Third Article'))
            );

            $this->assertEquals($expected, $result);
        }
    }

测试控制器

CakePHP 提供了特别的 ControllerTestCase 类。用该类作为控制器测试 用例的基类,让你可以使用 testAction() 方法,使测试用例更简单。 ControllerTestCase 让你容易地模拟组件和模型,以及象 redirect() 这样可能更难测试的方法

    class ArticlesControllerTest extends ControllerTestCase {
        public $fixtures = array('app.article');

        public function testIndex() {
            $result = $this->testAction('/articles/index');
            debug($result);
        }

        public function testIndexShort() {
            $result = $this->testAction('/articles/index/short');
            debug($result);
        }

        public function testIndexShortGetRenderedHtml() {
            $result = $this->testAction(
               '/articles/index/short',
                array('return' => 'contents')
            );
            debug($result);
        }

        public function testIndexShortGetViewVars() {
            $result = $this->testAction(
                '/articles/index/short',
                array('return' => 'vars')
            );
            debug($result);
        }

        public function testIndexPostData() {
            $data = array(
                'Article' => array(
                    'user_id' => 1,
                    'published' => 1,
                    'slug' => 'new-article',
                    'title' => 'New Article',
                    'body' => 'New Body'
                )
            );
            $result = $this->testAction(
                '/articles/index',
                array('data' => $data, 'method' => 'post')
            );
            debug($result);
        }
    }

testAction 方法的 第一个参数应当总是要测试的网址(URL)。CakePHP 会创建一个请求,调度(dispatch) 控制器和动作

在测试包含 redirect() 方法和其它在重定向(redirect)之后的代码,通常更好的 做法是在重定向时返回。这是因为,redirect() 方法在测试中是模拟的,并不像正常 状态是存在的。它不会使代码退出,而是继续运行重定向之后的代码

    App::uses('AppController', 'Controller');

    class ArticlesController extends AppController {
        public function add() {
            if ($this->request->is('post')) {
                if ($this->Article->save($this->request->data)) {
                    // 如果没有return,测试代码会继续执行下去
                    return $this->redirect(array('action' => 'index'));
                }
            }
            // 更多代码
        }
    }

第二个参数是传递的请求数据和方法

    public function testAdding() {
        $data = array(
            'Post' => array(
                'title' => 'New post',
                'body' => 'Secret sauce'
            )
        );
        // 默认是post,如果get方法,则特别指定
        $this->testAction('/posts/add', array('data' => $data, 'method' => 'get'));
        // 一些断言(*assertion*)。
    }

选择返回类型

  • vars 得到设置的视图(view)变量。
  • view 得到渲染的不含布局(layout)的视图。
  • contents 得到渲染的包含布局(layout)的视图。
  • result 得到控制器动作的返回值。可用于测试 requestAction 方法。

默认值为 result。只要返回类型不是 result,也可以在测试用例中用属性访问 其它返回类型:

    public function testIndex() {
        $this->testAction('/posts/index');
        $this->assertInternalType('array', $this->vars['posts']);
    }

测试返回 JSON 响应的控制器

    class MarkersControllerTest extends ControllerTestCase {
        public function testIndex() {
            $result = $this->testAction('/markers/index.json');
            $result = json_decode($result, true);
            $expected = array(
                'Marker' => array('id' => 1, 'lng' => 66, 'lat' => 45),
            );
            $this->assertEquals($expected, $result);
        }
    }

测试视图

通常大部分应用程序不会直接测试它们的 HTML 代码。这么做经常会导致脆弱、难以维护的 测试套件,容易遭到破坏。在使用 ControllerTestCase 编写功能性测试时, 可以设置 return 选项为 ‘view’ 来检视渲染的视图内容

创建测试套件

如果你想要几个测试一起运行,可以创建测试套件。一个测试套件由多个测试用例组成

如果想要为所有的模型测试创建测试套件,可以创建app/Test/Case/AllModelTest.php

    class AllModelTest extends CakeTestSuite {
        public static function suite() {
            $suite = new CakeTestSuite('All model tests');
            $suite->addTestDirectory(TESTS . 'Case/Model');
            return $suite;
        }
    }

以上代码会把目录 /app/Test/Case/Model/ 中所有的测试用例组织在一起。要添加 单个文件,使用 $suite->addTestFile($filename); 方法

递归添加一个目录中的所有测试或测试套件:$suite->addTestDirectoryRecursive(TESTS . 'Case/Model');$suite->addTestDirectoryRecursive(TESTS . 'Case');

你可能感兴趣的:(CakePHP的测试方法)