Merge branch 'master' of https://git.shagain.club/shulang/webman
This commit is contained in:
commit
377efca3cb
|
@ -82,4 +82,8 @@ JwtToken.php 需要修改成如下
|
|||
|
||||
```
|
||||
composer i
|
||||
```
|
||||
phpunit 单元测试
|
||||
```
|
||||
./vendor/bin/phpunit --bootstrap support/bootstrap.php --testdox tests/TestUser.php
|
||||
```
|
|
@ -66,5 +66,8 @@
|
|||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
"prefer-stable": true,
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6"
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
class HttpBase
|
||||
{
|
||||
// 单例复用 HTTP 客户端
|
||||
protected static $client = null;
|
||||
|
||||
/**
|
||||
* 获取 Guzzle 客户端(支持动态设置 base_uri)
|
||||
*
|
||||
* @param string|null $baseUri
|
||||
* @return Client
|
||||
*/
|
||||
protected static function get_client($baseUri = null)
|
||||
{
|
||||
if (self::$client === null) {
|
||||
self::$client = new Client([
|
||||
'timeout' => 60, // 设置请求超时时间为60秒
|
||||
'connect_timeout' => 30, // 设置连接超时时间为30秒
|
||||
'curl' => [
|
||||
CURLOPT_FRESH_CONNECT => false,
|
||||
CURLOPT_FORBID_REUSE => false,
|
||||
],
|
||||
'headers' => [
|
||||
'Connection' => 'keep-alive',
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
'base_uri' => $baseUri ?? 'http://127.0.0.1:8787',
|
||||
]);
|
||||
}
|
||||
return self::$client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 (支持 JSON 和 FORM)
|
||||
*
|
||||
* @param array $data 请求数据
|
||||
* @param string $url 请求地址(不包括 base_uri)
|
||||
* @param string $method 请求方法(GET/POST)
|
||||
* @param string|null $baseUri 动态设置 baseUri(可选)
|
||||
* @param string $contentType 数据格式(json/form)
|
||||
* @return array|false 响应的 JSON 数据或 false
|
||||
*/
|
||||
public static function httpclient($data, $url, $method = 'POST', $baseUri = null, $contentType = 'json')
|
||||
{
|
||||
$client = self::get_client($baseUri);
|
||||
|
||||
try {
|
||||
$options = [];
|
||||
|
||||
if (strtoupper($method) === 'GET') {
|
||||
// GET 请求将数据作为查询参数
|
||||
$options['query'] = $data;
|
||||
} else {
|
||||
if ($contentType === 'json') {
|
||||
// 发送 JSON 格式的数据
|
||||
$options['json'] = $data;
|
||||
} elseif ($contentType === 'form') {
|
||||
// 发送 form-data 格式的数据
|
||||
$options['form_params'] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
$response = $client->request(strtoupper($method), $url, $options);
|
||||
|
||||
// 解析 JSON 响应
|
||||
$body = $response->getBody()->getContents();
|
||||
return json_decode($body, true);
|
||||
} catch (RequestException $e) {
|
||||
// echo "HTTP 请求失败: " . $e->getMessage() . "\n";
|
||||
if ($e->hasResponse()) {
|
||||
$response = $e->getResponse();
|
||||
$statusCode = $response->getStatusCode(); // 获取 HTTP 状态码
|
||||
$body = $response->getBody()->getContents(); // 获取响应体
|
||||
|
||||
// echo "状态码: " . $statusCode . "\n";
|
||||
// echo "响应体: " . $body . "\n";
|
||||
}
|
||||
return $statusCode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
namespace Tests;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TestConfig extends TestCase
|
||||
{
|
||||
// public function testAppConfig()
|
||||
// {
|
||||
// $config = config('app');
|
||||
// self::assertIsArray($config);
|
||||
// self::assertArrayHasKey('debug', $config);
|
||||
// self::assertIsBool($config['debug']);
|
||||
// self::assertArrayHasKey('default_timezone', $config);
|
||||
// self::assertIsString($config['default_timezone']);
|
||||
// }
|
||||
/**
|
||||
* @dataProvider additionProvider
|
||||
*/
|
||||
public function testAdd($a, $b, $expected)
|
||||
{
|
||||
// $this->assertSame($expected, $a + $b);
|
||||
$this->assertEquals($expected, $a + $b);
|
||||
}
|
||||
|
||||
public function additionProvider()
|
||||
{
|
||||
return [
|
||||
'adding zeros' => [0, 0, 0], // 0 + 0 = 0 pass
|
||||
'zero plus one' => [0, 1, 1], // 0 + 1 = 1 pass
|
||||
'one plus zero' => [1, 0, 1], // 1 + 0 = 1 pass
|
||||
'one plus one' => [1, 1, 2], // 1 + 1 = 2 pass
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use app\model\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
use Tests\HttpBase;
|
||||
|
||||
use Tests\Utils\ClassMethodScanner;
|
||||
|
||||
class TestJwt extends TestCase
|
||||
{
|
||||
/**
|
||||
* Summary of testJwt
|
||||
* @param mixed $url
|
||||
* @param mixed $expected
|
||||
* @return void
|
||||
* @dataProvider additiontJwt
|
||||
*/
|
||||
public function testJwt($url, $expected)
|
||||
{
|
||||
$data = [
|
||||
"username" => '',
|
||||
"password" => '',
|
||||
];
|
||||
$res = HttpBase::httpclient($data, $url, 'POST', null, 'form');
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
||||
public function additiontJwt()
|
||||
{
|
||||
$scanner = new ClassMethodScanner();
|
||||
|
||||
// 指定目录路径
|
||||
$directory = 'app/controller/api/';
|
||||
|
||||
// 获取类和方法
|
||||
$classesAndMethods = $scanner->getClassesAndMethods($directory);
|
||||
|
||||
$url_array = [];
|
||||
// 输出所有类和方法
|
||||
foreach ($classesAndMethods as $url) {
|
||||
// 拼接描述并将状态码 401 加入
|
||||
$url_array['测试不登录接口访问 ' . $url] = [$url, 401];
|
||||
}
|
||||
return $url_array;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use app\model\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
use Tests\HttpBase;
|
||||
|
||||
use Tests\Utils\ClassMethodScanner;
|
||||
|
||||
class TestUser extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider additiontLogin
|
||||
*/
|
||||
public function testLogin($phone, $password, $expected)
|
||||
{
|
||||
$data = [
|
||||
"username" => $phone,
|
||||
"password" => $password,
|
||||
];
|
||||
$res = HttpBase::httpclient($data, '/api/user/login', 'POST', null, 'form');
|
||||
$this->assertEquals($expected, $res['code']);
|
||||
}
|
||||
|
||||
public function additiontLogin()
|
||||
{
|
||||
$random_users = User::inRandomOrder()->first();
|
||||
$banned_users = User::where('status', 0)->inRandomOrder()->first();
|
||||
return [
|
||||
'正确用户登录' => [$random_users->username, 'cCqQgG9koky^#uDFXllNUM46@jrI7KfsL77IIWwt', 1],
|
||||
'错误用户登录' => [$random_users->username, '12345', 0],
|
||||
'被封禁用户登录' => [$banned_users->username, 'cCqQgG9koky^#uDFXllNUM46@jrI7KfsL77IIWwt', 0],
|
||||
'通用密码登录' => [$random_users->username, 'cCqQgG9koky^#uDFXllNUM46@jrI7KfsL77IIWwt', 1],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Utils;
|
||||
|
||||
class ClassMethodScanner
|
||||
{
|
||||
// 递归获取指定目录下所有 PHP 文件
|
||||
private function getPhpFiles($dir)
|
||||
{
|
||||
$phpFiles = [];
|
||||
$files = scandir($dir);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file === '.' || $file === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filePath = $dir . DIRECTORY_SEPARATOR . $file;
|
||||
|
||||
// 如果是目录,则递归调用
|
||||
if (is_dir($filePath)) {
|
||||
$phpFiles = array_merge($phpFiles, $this->getPhpFiles($filePath));
|
||||
} elseif (pathinfo($filePath, PATHINFO_EXTENSION) === 'php') {
|
||||
$phpFiles[] = $filePath;
|
||||
}
|
||||
}
|
||||
|
||||
return $phpFiles;
|
||||
}
|
||||
|
||||
// 获取指定目录下的所有文件的 URL
|
||||
public function getClassesAndMethods($dir)
|
||||
{
|
||||
$files = $this->getPhpFiles($dir);
|
||||
$classesAndMethodsUrl = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
$fileCont = file_get_contents($file); // 读取文件内容
|
||||
|
||||
// 匹配 @Apidoc\Url 注解中的 URL
|
||||
$pattern = '/@Apidoc\\\\Url\("([^"]+)"\)/';
|
||||
preg_match_all($pattern, $fileCont, $matches);
|
||||
|
||||
// 匹配 protected $noNeedLogin 数组中的元素
|
||||
preg_match('/protected\s+\$noNeedLogin\s*=\s*\[(.*?)\];/', $fileCont, $noNeedLogin);
|
||||
|
||||
// 处理 noNeedLogin 数组
|
||||
$noNeedLoginElements = [];
|
||||
if (!empty($noNeedLogin[1])) {
|
||||
preg_match_all("/'([^']+)'/", $noNeedLogin[1], $noNeedLoginElements);
|
||||
$noNeedLoginElements = $noNeedLoginElements[1]; // 获取到数组中的元素
|
||||
}
|
||||
|
||||
// 将匹配到的 URL 添加到结果数组中
|
||||
if (!empty($matches[1])) {
|
||||
foreach ($matches[1] as $url) {
|
||||
// 检查 URL 是否不包含在 noNeedLogin 数组中
|
||||
if(!$this->stringContainsArray($url, $noNeedLoginElements)) {
|
||||
$classesAndMethodsUrl[] = $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $classesAndMethodsUrl;
|
||||
}
|
||||
|
||||
// 检查字符串是否包含数组中的元素
|
||||
private function stringContainsArray($string, $array)
|
||||
{
|
||||
return !empty(array_filter($array, function($substring) use ($string) {
|
||||
return strpos($string, $substring) !== false;
|
||||
}));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue