Slim
是一个PHP 微框架,极度精简高效 Slim官网
Guzzle
是一个PHP的HTTP客户端,用来轻而易举地发送请求,并集成到我们的WEB服务上。Guzzle
PHPUnit
单元测试组件,很多人都知道,但是应该很多人也都没用过。PHPUnit
我结合slim
+illuminate/database
+guzzle
+PHPUnit
实现API开发,测试的开发框架。
系统目录结构
app:应用目录
app/src:应用业务代码
app/src/controllers:控制器代码
app/src/models:模型代码
app/tests:单元测试代码目录
dependencies.php:依赖注入配置文件
helpers.php:系统公共函数文件
middlewares.php:中间价
routes.php:路由配置文件
settings.php:框架配置,数据库设置文件
public:项目单一入口目录
vendor:组件目录,使用composer自动存放的if
composer.json
内容
{
"require": {
"slim/slim": "^3.8",
"illuminate/database": "^5.4",
"guzzlehttp/guzzle": "^6.3",
"psr/log": "^1.0",
"phpunit/phpunit": "^6.2"
},
"autoload": {
"psr-4": {
"app\\": "app/src"
},
"files" : ["app/helpers.php"]
}
}
具体使用流程
首先配置路由,在routes.php 文件中写下面的代码
$app->get('/user/{name}', app\controllers\UserController::class.':user');
写业务代码
Controller: <?php namespace app\controllers;
class Controller
{
/**
* 构造响应数据数组
* @param array $data 返回的数据
* @param integer $code 0表示正常,1表示错误
* @param string $msg 错误消息提示
* @return array 响应数据
*/
public function createResponse($data,$code=0,$msg='')
{
return array (
'data' => $data,
'code' => $code,
'msg' => $msg
);
}
}
UserController:
<?php
namespace app\controllers;
use app\models\Users;
class UserController extends Controller
{
public function user($request, $response, $args) {
$user = Users::where('username',$args['name'])->first();
$data = $this->createResponse($user);
return $response->withJson($data);
}
}
Model:
<?php
namespace app\models;
use \Illuminate\Database\Eloquent\Model;
class Users extends Model
{
}
写测试文件
<?php
namespace app\tests;
use PHPUnit\Framework\TestCase;
use GuzzleHttp\Client;
class UserTest extends TestCase
{
private $client;
public function setUp()
{
$this->client = new Client([
'base_uri' => 'http:/z.slim.com',
'http_errors' => false, #设置成 false 来禁用HTTP协议抛出的异常(如 4xx 和 5xx 响应),默认情况下HTPP协议出错时会抛出异常。
]);
}
public function testUser()
{
$response = $this->client->get('/user/vilay');
$this->assertEquals(200, $response->getStatusCode()); //断言状态码为200
$body = $response->getBody();
$data = json_decode($body, true);
$this->assertArrayHasKey('code', $data); //断言返回数据中有code字段
$this->assertArrayHasKey('msg', $data);
$this->assertArrayHasKey('data', $data);
$this->assertEquals(0, $data['code'],'数据错误'); //断言返回数据code字段值为0,如果不等于1则提示数据错误
$this->assertInternalType('array', $data['data']); //断言返回数据data类型为数组
}
}
执行测试文件
如果有在__系统全局安装PHPUnit__, 在项目目录下执行:phpunit app/tests/UserTest.php
如果只在__单个项目__中使用,执行命令
chmod a+x vendor/bin/phpunit
chmod a+x vendor/phpunit/phpunit/phpunit
sh vendor/bin/phpunit app/tests/UserTest.php
实践中遇到的坑:
单元测试文件执行问题:上面说了系统全局使用和项目局部使用,在项目局部使用,网上搜索资料的时候有些教程是用命令执行php vendor/bin/phpunit app/tests/UserTest.php
,这个命令可能是早期版本的,我使用的是6.x的,需要给可执行权限,然后执行sh vendor/bin/phpunit app/tests/UserTest.php
单元测试文件自动加载的问题:由于没有走单一入口文件,刚开始是在单元测试,也就是UserTest.php
,文件头部引入require_once 'vendor/autoload.php'
,但是这种实现方式太坑了,还好PHPUnit
提供了个bootstrap
属性,解决方案是修改项目目录的phpunit.xml
,示例
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.7/phpunit.xsd"
bootstrap="vendor/autoload.php"
backupGlobals="false"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true">
<testsuite>
<directory suffix="Test.php">tests</directory>
</testsuite>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="build/coverage/html" title="phpDox"
charset="UTF-8" highlight="true" lowUpperBound="60" highLowerBound="90"/>
</logging>
</phpunit>