基于 Laravel 框架的 phpunit 单元测试爬坑记录

基于 Laravel 框架的 phpunit 单元测试爬坑记录

单元测试的目录结构

  • 测试文件一般位于项目根目录下的 tests 文件夹或者 models 下的项目中的 tests 文件夹。
  • 在命令行中执行以下命令:

这种方式生成的测试文件创建在项目根目录下的 tests/Feature

php artisan make:test DemoTest //可以生成 DemoTest.php 测试文件

在命令行中执行以下命令:

执行所有 test 方法

phpunit

执行所有 BackendTest.php 里的 test 方法

phpunit  tests/Feature/BackendTest.php 

测试代码编写

  1. 带入参数请求访问接口
  2. 获取返回值断言

举个栗子:

class AccountTest extends TestCase
//所有测试类必须基于TestCase
{
    /**
     * 测试用户信息详情页接口
     * 所有测试方法命名,必须以 test 小写开头命名
     * 或者在注释中写明标注 @test
     * @return mixed
     */
    public function testuserinfo_detail()
    {
        $response = $this->get('http://ideabuy.xin.cn/api/userinfo-detail',$this->authHeader)
        // $this->assertEquals('ture',$response->getcontent());
        //当下面断言失败时,将这行代码取消注释,将下面注释,上面代码最后加上分号,再次运行,即可看到报错具体信息。
            ->assertJsonFragment([
                'msg'=>'查询成功',
            //断言返回的JSON值中包含一个 msg:‘查询成功’ 的对象 
            ]);
    }
}

介绍几个接口访问方式

  • GET 请求
get($uri, array $headers = []);
  • POST 请求
post($uri, array $data = [], array $headers = []);
  • JSON 请求
json('POST', $uri, $data, $headers);
  • CALL 请求
call('PUT', $uri, $data, [], [], $server);
  • 获取接口返回值方法
$response->getcontent();
$response->getOriginalContent();

简单列几个常见的断言方法,具体更多的断言方法–点此跳转链接

  • assertJsonFragment and assertJsonFragment

判断返回的JSON数值里是否包含$params
当返回值有 json 格式的 msg 信息

$this->assertJsonFragment($params) ;
$this->assertJsonFragment([ 'msg' => '头像修改成功']);
  • assertJsonStructure and assertJsonStructure

判断返回的JSON数据里是否包含$params数据结构
当返回值中不存在 msg 时(例如用户详情查出来基本为 data 时)可以用来判断是否存在数据。

$this->assertJsonStructure($params);
$this->assertJsonStructure(['data'=>[]]);
  • assertEquals

断返回值是否与$params相同

$this->assertEquals(1, $result['code']);
  • assertResponseOk

断言客户端返回的响应状态码是否是200

$this->assertResponseOk();

token+版本信息

由于大部分接口都做了用户登录的判断,所以在对接口进行测试的时候需要带上用户登录的信息(token+版本信息)。

  • 获取token的时候(即模拟登陆的时候–userlogin方法)如果报 ==data== 错误,先检查一下本地环境是不是需要全拼路由才能访问接口

例:

$response = $this->get('http://ideabuy.xin.cn/backend/constype-list', $this->authHeader)
  • 如果token可以打印的情况下,还报错。检查一下 setup 方法是否添加了刷新语句。

例:

$this->refreshApplication();
  • 下面的代码举了一个userlogin登录的操作

backend登录可以仿照下面操作,在 Common 里的方法中添加一个adminlogin,然后继承这个类去调用登录后的token

嗯,我还是贴代码吧:
路径:test/common/ApiTestCase.php

   public function adminLogin($params = [])
    {
        $response = $this->post(
            'http://ideabuy.xin.cn/backend/admin-login',
            $params
        );

        $admins = $response->getOriginalContent();

        return $admins;
    }

路径:test/BackendTest.php

  public function setUp()
   {
        parent::setUp();

        $this->params = $this->readyApiParams();
        $admin = $this->adminLogin($this->params['login']);
        $this->admin = $admin;
        $this->authHeader = $this->headers($admin);

        $this->refreshApplication();
    }
  • 接下来在你写的test方法里的头部信息就可以直接$this->authHeader 进行调用了!
    类似于这样:
$response = $this->get('http://ideabuy.xin.cn/backend/order-detail?order_id=282',  $this->authHeader)

附上登录用例代码:

路径:test/common/ApiTestCase.php

<?php

namespace Modules\Api\Tests\Common;

use Tests\TestCase;

/**
 * Class ApiTestCase
 * @package Modules\Api\Tests\Common
 */
class ApiTestCase extends TestCase
{
    /**
     * User login
     * @param array $params
     * @return mixed
     */
    public function userLogin($params = [])
    {
        $response = $this->post(
        #路由看个人环境配置是否需要加上 http://ideabuy.xin.cn
            'http://ideabuy.xin.cn/api/user-login',
            $params,
        #调用下面拼接token的方法
            $this->headers()
        );

        $users = $response->getOriginalContent();

        return $users;
    }

    /**
     * Setting request header
     * @param null $user
     * @param array $addition
     * @return array
     */
    protected function headers($user = null, $addition = [])
    {
        #添加版本号头部信息
        $headers = ['Accept' => 'application/vnd.ideabuy.v1+json'];
        #拼接 token
        if (!is_null($user)) {
            $headers['Authorization'] = 'Bearer '.$user['data']['token'];
        }

        if($addition){
            $headers = array_merge($headers,$addition);
        }

        return $headers;
    }

}

路径:test/AccountTest.php

<?php

namespace Modules\Api\Tests;

use Modules\Api\Tests\Common\ApiTestCase;

class AccountTest extends ApiTestCase
{
    public $authHeader;
    public $params;
    public $data;
    public $user;


    /**
     * ready for data & params
     */
    public function setUp()
    {
        #每个test方法之前都会调用一次这个方法
        parent::setUp();

        $this->params = $this->readyApiParams();
        /** Get auth info include token  */
        #调用用户登录的操作
        $user = $this->userLogin($this->params['login']);
        $this->user = $user;
        #获取用户 token
        $this->authHeader = $this->headers($user);

        #刷新应用。该操作由TestCase的setup()方法自动调用,不然会使用过期的token
        $this->refreshApplication();
    }


    /**
     * Ready for test params
     */
    protected function readyApiParams()
    {
        #这个方法用来放test里需要的参数
        $params = [];

        /** login params for test **/

        $login = [
            'user_mobile' => '13777979098',
            'user_password' => 'a12345678'
        ];
        $params['login'] = $login;

        /** register user params for test **/

        $register = [
            'user_mobile' => '13777979098',
            'user_password' => 'a12345678',
            'confirm_password' => 'a12345678',
            'code' => '1234'
        ];
        $params['register'] = $register;

        /** setting user paypassword params for test **/

        $payPassword = ['pay_password' => 'b11111111'];
        $params['payPassword'] = $payPassword;

        return $params;
    }

    /**
     * Clean  test data
     */
    protected function cleanData()
    {
        //todo logic data
        //Artisan::call('migrate:reset');
    }

    /**
     * this is case for user login
     */
    public function testUserLogin()
    {
        $this->assertEquals(1, $this->user['code']);
    }


    /**
     * This is case for setting pay password
     * @test
     */
    public function SetPayPassword()
    {

        $response = $this->post(
            'http://ideabuy.xin.cn/api/user-setpaypwd',
                $this->params['payPassword'],
                #获取token
                $this->authHeader
        );

        $result = $response->getOriginalContent();
        #getOriginalContent()是将返回值转成数组,getcontent()是直接将对象返回
        $this->assertEquals(1, $result['code']);

    }


    /**
     * Drop something test data
     */
    public function tearDown()
    {
        $this->cleanData();

        parent::tearDown();

    }

}

欢迎大家给意见和补充。

本作品采用《CC 协议》,转载必须注明作者和本文链接
附言 1  ·  4年前

文档:基于 Laravel 框架的 phpunit 单元测试...
链接:http://note.youdao.com/noteshare?id=606bd3...

本帖由系统于 6年前 自动加精
小烦
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

内容不错, 格式有点乱

5年前 评论

可以单独执行测试某个方法或者接口吗? phpunit tests/Feature/BackendTest.php 这个是执行test文件里面所有方法

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!