Laravel 单元测试实战(1)- 以电商优惠券设计为例编写单元测试
Laravel 单元测试实战(1)- 以电商优惠券设计为例编写单元测试
单元测试的理解
本文理解的单元测试,不含任何外部系统,包括数据库。
需求
为了写这个文章,虚拟一个电商项目,要求,每次用户购买商品时,自动帮用户从他自己的多张优惠券中选择一张优惠力度最高的优惠券。
优惠券有满减固定金额,满减折扣两种。
表结构:
用户表 users
字段 | 类型 | 含义 |
---|---|---|
id | int | 自增主键 |
user_name | string | 用户名,登录用 |
商品表 goods
字段 | 类型 | 含义 |
---|---|---|
id | int | 自增主键 |
product_name | string | 商品名 |
price | decimal(8,2) | 价格 |
店铺表 shops
字段 | 类型 | 含义 |
---|---|---|
id | int | 自增主键 |
shop_name | string | 店铺名 |
商品店铺关联表(多对多)shop_goods
字段 | 类型 | 含义 |
---|---|---|
id | int | 自增主键 |
shop_id | int | 店铺id |
goods_id | int | 商品id |
系统优惠券表 system_coupons
字段 | 类型 | 含义 |
---|---|---|
id | int | 自增主键 |
coupon_name | string | 优惠券名称 |
type | tinyint | 1满减固定额度,2满减折扣 |
coupon_value | decimal(8,2) | 满减比如5表示可以减去5元,折扣比如0.8表示8折 |
用户优惠券表
字段 | 类型 | 含义 |
---|---|---|
id | int | 自增主键 |
user_id | int | 用户id |
system_coupon_id | int | 对应的系统优惠券id |
coupon_name | string | 优惠券名称 |
type | tinyint | 1满减固定额度,2满减折扣 |
coupon_value | decimal(8,2) | 满减比如5表示可以减去5元,折扣比如0.8表示8折 |
condition_money | decimal(8,2) | 满减的条件,一个订单的总金额大于等于此值 |
订单表
略
框架
Larave 8.5
github 项目地址
git clone https://gitee.com/three_kingdoms_of_zhang/unit_test_practice.git
composer install
git checkout v1.0
代码是完整的,包括迁移,模型类,和全部功能。
需求分析
用户在商品页面选择商品和数量,加入购物车,可以选择多种不同的商品,最后点击购买,此时前端调用接口,会获得一张优惠券,然后把总价和系统自动选择的优惠券显示在第二个页面(注意测试订单并未生成)。
本文的目的就是写这个接口,和对这个接口的部分单元测试。
因为接口实际调用数据库,这部分只能通过集成测试来实现。
控制器编写,
<?php
namespace App\Http\Controllers\Order;
use App\Http\Controllers\Controller;
use App\Models\Goods;
use App\Models\UserCoupon;
use App\Services\Order\ServiceOrder;
use Illuminate\Support\Collection;
class OrderController extends Controller
{
public function find_user_coupon(Request $request, ServiceOrder $serviceOrder)
{
$user_id = $request->input('user_id');
// 用户持有的优惠券。
$user_coupon_records = UserCoupon::query()
->where('user_id', $user_id)
->where('use_status', 0)
->get();
// 购物车格式
// $shopping_cart = [
// [
// 'goods_id' => 1,
// 'count' => 3,
// ],
// [
// 'goods_id' => 2,
// 'count' => 1,
// ],
// [
// 'goods_id' => 3,
// 'count' => 2,
// ],
// ];
$shopping_cart = $request->input('shopping_cart');
//根据购物车查商品。
$goods_records =collect([]);
foreach ( $shopping_cart as $goods_count ){
$goods_records->push( Goods::findOrFail($goods_count['goods_id']) );
}
//根据购物车内容,及查出的商品价格,还有用户已有的优惠券。去查找最优的优惠券。
$user_coupon_record = $serviceOrder->find_user_coupon_from_shopping_cart(
$shopping_cart, $goods_records ,$user_coupon_records
);
$data =[
'code' =>0,
'data' => $user_coupon_record,
];
return response()->json($data)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
}
public function test()
{
}
}
service 编写
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2022/9/23
* Time: 13:14
*/
namespace App\Services\Order;
use Illuminate\Support\Collection;
class ServiceOrder
{
/**
* 根据购物车信息,和已有的优惠券,查找最优惠的一张优惠券。
*
* @param array $shopping_cart 前端传来的商品信息。
* // 购物车格式
* $shopping_cart = [
* [
* 'goods_id' => 1,
* 'count' => 3,
* ],
* [
* 'goods_id' => 2,
* 'count' => 1,
* ],
* [
* 'goods_id' => 3,
* 'count' => 2,
* ],
* ];
*
* @param Collection $goods_records 自己查的数据库信息,商品的。
* @param Collection $user_coupon_records 自己查的用户优惠券信息。
*
* @return [
* 'saved_money' => 0, //优惠券自身的等价金额
* 'user_coupon_record' => [ //优惠券记录,或者null
* 'id' => 4,
* 'type' => 2,
* 'coupon_value' => 0.9,
* 'condition_money' => 50,
* ]
* ]
*/
public function find_user_coupon_from_shopping_cart(array $shopping_cart,Collection $goods_records, Collection $user_coupon_records):array
{
return [];
}
}
单元测试编写
<?php
namespace Tests\Unit;
use App\Services\Order\ServiceOrder;
use PHPUnit\Framework\TestCase;
class ServiceOrderTest extends TestCase
{
/**
* 返回一张满减折扣的优惠券。
*
* @return void
*/
public function test_find_user_coupon_from_shopping_cart_return_right()
{
$service = new ServiceOrder();
$shopping_cart = [
[
'goods_id' => 1,
'count' => 3,
],
[
'goods_id' => 2,
'count' => 1,
],
[
'goods_id' => 3,
'count' => 2,
],
];
// 总价 30+ 20 + 60 = 110
$goods_records = [
[
'id' => 1,
'price' => 10,
],
[
'id' => 2,
'price' => 20,
],
[
'id' => 3,
'price' => 30,
],
];
// 110的一折是 11元,优惠最大,应该返回第4条记录。
$user_coupon_records = [
[
'id' => 1,
'type' => 1,
'coupon_value' => 5,
'condition_money' => 1000,
],
[
'id' => 2,
'type' => 1,
'coupon_value' => 5,
'condition_money' => 50,
],
[
'id' => 3,
'type' => 1,
'coupon_value' => 6,
'condition_money' => 50,
],
[
'id' => 4,
'type' => 2,
'coupon_value' => 0.9,
'condition_money' => 50,
],
];
$result = $service->find_user_coupon_from_shopping_cart( $shopping_cart, collect($goods_records), collect($user_coupon_records ) );
$result_expect = [
'saved_money' =>11,
'user_coupon_record'=>[
'id' => 4,
'type' => 2,
'coupon_value' => 0.9,
'condition_money' => 50,
],
];
$this->assertEquals($result['saved_money'], $result_expect['saved_money']);
$this->assertEquals($result['user_coupon_record']['id'], $result_expect['user_coupon_record']['id']);
}
}
执行单元测试
./vendor/bin/phpunit ./tests/Unit/ServiceOrderTest.php
应显示测试失败。
总结:
先把代码的控制器写出来,service 类必须定义好入参,返回格式,但是函数体为空,然后写好单元测试代码。
按惯例,先执行一下测试,查看到错误。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: