使用 Laravel 进行商品功能测试
在查看Laravel的HTTP测试,在开发过程中,进行相关的功能测试是有必要的。
以下是我进行的相关api功能测试:
通过命令php artisan make:test GoodsTest
创建一个功能测试类
创建的默认页面如下:
class GoodsTest extends TestCase
{
/**
* A basic feature test example.
*
* @return void
*/
public function testExample()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
在调用相关接口时,首先需要进行用户认证,首先我需要获取用户登录token,并在请求api接口时,在请求头部添加token,以此完成用户认证。
定义登录路由
Route::group(['namespace' => 'Auth'], function () {
//提交登录信息
Route::any('/login', 'LoginController@login')->name('admin.login');
});
登录接口代码如下:
public function login(Request $request)
{
$info = $request->input('info');
$token = Auth::guard('admin')->attempt(['email'=>$info['email'],'password'=>$info['password']],true);
$admin = Auth::guard('admin')->user();
if(!$admin){
return $this->failed('账号密码错误,请重新输入');
}
return $this->success($token);
}
以上代码为判断用户账号密码是否正确,若正确返回token,响应状态为200;否则响应状态为400;
编写添加模拟登录测试方法
/**
* @test
* @return void
* 模拟用户登录
*/
public function login()
{
$data = [
'email' => 'test@qq.com',
'password' => '123456'
];
$response = $this->json('GET',route('admin.login'),['info'=>$data]);
$response->assertStatus(200);
$token = $response->json();
return $token;
}
这里以电商中的商品为例,对商品的创建,删除进行相关的功能测试。
商品创建测试
在以下例子中,首先通过获取Faker实例,Faker可以方便我们创建测试数据,详细使用可查看faker数据填充详解
创建商品的测试方法依赖于login方法,通过接受login方法传递的token,在请求创建商品接口中,传递token完成用户认证,并传递商品数据和商品属性数据。后验证接口状态是否正确,数据库是否存在相关商品数据和商品属性数据。
/**
* 添加商品数据
* @test
* @depends login
* @param $token
*/
public function create_goods($token)
{
// 获取 Faker 实例
$faker = \Faker\Factory::create();
//商品数据(商品名称,标题,描述,价格,商品详情,商品图片,属性总揽数组)
$info = [
'name' => $faker->sentence(5,true),
'title' => $faker->sentence(5,true),
's_desc' => $faker->text(),
'position' => $faker->numberBetween(1,100),
'good_grade' => $faker->numberBetween(1,5),
'weight' => $faker->numberBetween(100,1000),
'old_price' => $faker->randomFloat(2, 10, 15),
'sale_price' => $faker->randomFloat(2, 5, 10),
'content' => $faker->randomHtml(),
'mask' => $faker->imageUrl(),
'attr_list' => [
"a" => [
"index" => "a"
"name" => "color"
"list" => array:2 [
"k0" => "red"
"k1" => "yellow"
]
]
"b" => [
"index" => "b"
"name" => "size"
"list" => array:3 [
"k0" => "big"
"k1" => "small"
"k2" => "middle"
]
]
];
//属性预期数量
$attrCount = collect($info['attr_list'])->map(function ($attr){
return count($attr['list']);
})->reduce(function ($count,$item){
return $count*$item ? $count*$item : $item;
});
//商品属性数据(包括商品属性名,属性标识,旧价格,现价,商品sku,库存等)
$goodsAttr = [
[
'name'=>'red/big',
'attr'=>"[\"ak0\",\"bk0\"]",
'sku'=>$faker->uuid,
'old_price'=>$faker->randomFloat(2, 10, 15),
'price'=>$faker->randomFloat(2, 10, 15),
'count'=>$faker->numberBetween(1, 100),
'weight'=>$faker->numberBetween(1, 100)
],
[
'name'=>'red/small',
'attr'=>"[\"ak0\",\"bk1\"]",
'sku'=>$faker->uuid,
'old_price'=>$faker->randomFloat(2, 10, 15),
'price'=>$faker->randomFloat(2, 10, 15),
'count'=>$faker->numberBetween(1, 100),
'weight'=>$faker->numberBetween(1, 100)
],
[
'name'=>'red/middle',
'attr'=>"[\"ak0\",\"bk2\"]",
'sku'=>$faker->uuid,
'old_price'=>$faker->randomFloat(2, 10, 15),
'price'=>$faker->randomFloat(2, 10, 15),
'count'=>$faker->numberBetween(1, 100),
'weight'=>$faker->numberBetween(1, 100)
],
[
'name'=>'yellow/big',
'attr'=>"[\"ak1\",\"bk0\"]",
'sku'=>$faker->uuid,
'old_price'=>$faker->randomFloat(2, 10, 15),
'price'=>$faker->randomFloat(2, 10, 15),
'count'=>$faker->numberBetween(1, 100),
'weight'=>$faker->numberBetween(1, 100)
],
[
'name'=>'yellow/small',
'attr'=>"[\"ak1\",\"bk1\"]",
'sku'=>$faker->uuid,
'old_price'=>$faker->randomFloat(2, 10, 15),
'price'=>$faker->randomFloat(2, 10, 15),
'count'=>$faker->numberBetween(1, 100),
'weight'=>$faker->numberBetween(1, 100)
],
[
'name'=>'yellow/middle',
'attr'=>"[\"ak1\",\"bk2\"]",
'sku'=>$faker->uuid,
'old_price'=>$faker->randomFloat(2, 10, 15),
'price'=>$faker->randomFloat(2, 10, 15),
'count'=>$faker->numberBetween(1, 100),
'weight'=>$faker->numberBetween(1, 100)
],
];
$response = $this->withHeader('Authorization',$token)
->json('POST','/api/goods',['info'=>$info,'goodsAttrTable'=>$goodsAttr,'attr_list'=>$info['attr_list']]);
$response->assertStatus(200);
$data = $response->json();
//若响应为200返回商品id
$goodsId = $data;
//判断商品是否存在数据库
$this->assertDatabaseHas('goods',['id'=>$goodsId]);
//判断数据库属性数量
$attr = GoodsAttr::where(['goods_id'=>$goodsId])->get()->toArray();
$this->assertEquals(count($attr),$attrCount);
}
在编写测试用例的过程中,一开始的传入数据和接口逻辑方面会存在相应问题,我可以通过编写这种测试用例的方式,不断完善测试用例和接口代码逻辑,以此完善代码的容错性和健壮性。这种开发方式也叫TDD(测试驱动开发).
强烈推荐阅读以下两篇文章:
重新认识 PHPUnit —— 从这里开始学习 PHP 下的 TDD(测试驱动开发)开发方法
使用 TDD 测试驱动开发来构建 Laravel REST API
最终在一步步的修改测试用例和接口代码后,通过不断重复执行phpunit --filter=GoodsTest
,最终达到我们测试的预期
删除商品测试
同样delete_goods测试方法依赖于login方法,我还对上个例子的create_goods方法做了调整,将创建的商品id返回,做为delete_goods的依赖,并对删除接口返回状态码进行断言,数据库软删除断言,获取商品详情接口进行状态码断言测试。
/**
* 删除商品
* @test
* @depends login
* @depends create_goods
* @param $token
* @param $id
*/
public function delete_goods($token,$id)
{
//商品id
$goodsId = $id;
$response = $this->withHeader('Authorization',$token)
->json('DELETE','/api/goods/'.$goodsId);
//验证状态码
$response->assertStatus(200);
//是否已被软删除
$this->assertSoftDeleted('goods',['id'=>$goodsId]);
//获取商品详情信息接口
$responseEdit = $this->withHeader('Authorization',$token)
->json('GET','/api/goods/'.$goodsId.'/edit');
$responseEdit->assertStatus(404);
}
使用模型工厂进行批量数据测试
通过命令php artisan make:factory GoodsFactory --model=Goods
生成商品的数据工厂
商品的基本数据可通过faker实例创建随机测试数据,但由于商品的属性总揽数据相对复杂,我通过自定义函数createAttr()创建生成相应数据。
//定义商品基本数据
$factory->define(Goods::class, function (Faker $faker) {
return [
'name' => $faker->sentence(5,true),
'title' => $faker->sentence(5,true),
's_desc' => $faker->text(),
'old_price' => $faker->randomFloat(2, 10, 15),
'sale_price' => $faker->randomFloat(2, 5, 10),
'content' => $faker->randomHtml(),
'mask' => $faker->imageUrl(),
'attr_list' => createAttr()
];
});
function createAttr()
{
//生成属性总揽
}
定义数据供给器
定义goods_data方法为数据供给器,在create_goods方法中使用数据供给器进行批量测试
/**
* 生成商品数据
*/
public function goods_data()
{
$goodsData = factory(Goods::class,10)->make()->toArray();
return $goodsData;
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: