Laravel 单元测试实战(2)- 编写实际功能并让代码测试通过
github 项目地址
git clone https://gitee.com/three_kingdoms_of_zhang/unit_test_practice.git
composer install
git checkout v2.0
代码是完整的,包括迁移,模型类,和全部功能。
service 实际编写,完成功能。
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
{
$total = $this->calculate_total_price( $shopping_cart, $goods_records );
$finded_user_coupon = $user_coupon_records
->filter(function ($user_coupon)use($total){ // 先根据总价过滤一部分
return $user_coupon['condition_money'] < $total;
})->map(function($user_coupon)use($total){ //开始计算节省金额
if ($user_coupon['type']==1) {
$user_coupon['saved_money'] = $user_coupon['coupon_value'] ;
}
if ($user_coupon['type']==2) {
$user_coupon['saved_money'] = $total * (1- $user_coupon['coupon_value']) ;
}
return $user_coupon;
})->sortByDesc(function ($user_coupon) { //根据节省金额倒序排
return $user_coupon['saved_money'];
})->first(); //取出第一个优惠券。
if ($finded_user_coupon) {
return [
'saved_money' => $finded_user_coupon['saved_money'], //优惠券自身的等价金额
'user_coupon_record' => [ //这个对应表中的一条记录。
'id' => $finded_user_coupon['id'],
'type' => $finded_user_coupon['type'],
'coupon_value' => $finded_user_coupon['coupon_value'],
'coupon_name' => $finded_user_coupon['coupon_name'],
]
];
}
return [
'saved_money' => 0,
'user_coupon_record' => null,
];
}
// 算总价
private function calculate_total_price(array $shopping_cart,Collection $goods_records):float
{
$total=0;
foreach( $shopping_cart as $shop_count){
$count = $shop_count['count'];
$unit_price=0;
foreach ( $goods_records as $goods ){
if ( $goods['id'] == $shop_count['goods_id'] ){
$unit_price = $goods['price'];
break;
}
}
if (!$unit_price) {
throw new \Exception('参数错误');
}
$total += $count * $unit_price;
}
return $total;
}
}
同时,发现了原先的单元测试代码要改一句话。断言节省金额的代码。
原先,
$this->assertEquals($result['saved_money'], $result_expect['saved_money']);
应改成:
$this->assertEqualsWithDelta($result['saved_money'], $result_expect['saved_money'],0.02);
执行单元测试
./vendor/bin/phpunit ./tests/Unit/ServiceOrderTest.php
会显示测试通过。
总结:
把功能实际写好,然后再次运行单元测试代码,这次通过了。
同时发现,单元测试必须修改,因为涉及到小数运算,无法精确,所以需要忽略一定的精度。
实际上,这接口就已经完成了。
但是,后面再写一个集成测试。带上数据库,彻底验证该代码的正确性。
另外,这里写的单元测试,覆盖的逻辑比较少,还需要测试边界条件,比如优惠券列表为空等情况。