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>

项目代码已经托管在github,有兴趣的可以看下.

slim-api