Laravel 单元测试实战(5)- 再次重构,将数组改为对象

Laravel 单元测试实战(5)- 再次重构,将数组改为对象

github 项目地址

git clone https://gitee.com/three_kingdoms_of_zhang/unit_test_practice.git
composer install
git checkout v6.0

代码是完整的,包括迁移,模型类,和全部功能。

需求

实际上,我们使用 lavarel 的模型类来实现功能,但是硬是用数组去凑,虽然可以,但是不够面向对象,所以想来想去,代码还是改一下,免得误导他人。

再次重构之后的代码

单元测试代码
<?php

namespace Tests\Unit;

use App\Services\Order\ServiceOrder;
use PHPUnit\Framework\TestCase;

class ServiceOrderTest extends TestCase
{

    /**
     * 二维数组变对象数组。
     *
     * @param $arr
     * @return false|mixed|string
     */
    public function json_change($arr)
    {
        $arr = json_encode($arr, JSON_UNESCAPED_UNICODE);
        $arr = json_decode($arr);
        return $arr;
    }

    /**
     * 设置购物车
     *
     * @return array
     */
    private function set_datas_to_shopping_carts(): array
    {
        return [
            [
                'goods_id' => 1,
                'count' => 3,
            ],
            [
                'goods_id' => 2,
                'count' => 1,
            ],
            [
                'goods_id' => 3,
                'count' => 2,
            ],
        ];
    }

    /**
     * 设置数据库里的商品
     */
    private function set_goods_records():array
    {
        $goods_records = [
            [
                'id' => 1,
                'price' => 10,
            ],
            [
                'id' => 2,
                'price' => 20,
            ],
            [
                'id' => 3,
                'price' => 30,
            ],
        ];
        return $goods_records;
    }

    /**
     * 返回一张满减折扣的优惠券。
     *
     * @return void
     */
    public function test_find_user_coupon_from_shopping_cart_return_manjian_right()
    {
        $service = new ServiceOrder();

        //设置购物车
        $shopping_carts = $this->set_datas_to_shopping_carts();
        $shopping_carts = $this->json_change($shopping_carts);

        // 设置商品数据。 总价 30+ 20 + 60 = 110
        $goods_records = $this->set_goods_records();
        $goods_records = $this->json_change($goods_records);

        // 110的一折是 11元,优惠最大,应该返回id=4记录。
        $user_coupon_records = [
            [
                'id' => 1,
                'type' => 1,
                'coupon_value' => 5,
                'coupon_name' => '优惠券1',
                'condition_money' => 1000,
                'use_status' =>0,
            ],
            [
                'id' => 2,
                'type' => 1,
                'coupon_value' => 5,
                'coupon_name' => '优惠券2',
                'condition_money' => 50,
                'use_status' =>0,
            ],
            [
                'id' => 4,
                'type' => 2,
                'coupon_value' => 0.9,
                'coupon_name' => '优惠券4',
                'condition_money' => 50,
                'use_status' =>0,
            ],
            [
                'id' => 5,
                'type' => 1,
                'coupon_value' => 6,
                'coupon_name' => '优惠券5',
                'condition_money' => 50,
                'use_status' =>0,
            ],

        ];
        $user_coupon_records = $this->json_change($user_coupon_records);

        $result = $service->find_user_coupon_from_shopping_cart( $shopping_carts, collect($goods_records),
            collect($user_coupon_records ) );

        $result_expect = [
            'saved_money' =>11,
            'user_coupon_record'=>(object)[
                'id' => 4,
                'type' => 2,
                'coupon_value' => 0.9,
                'condition_money' => 50,
            ],
        ];
        $this->assertEqualsWithDelta($result['saved_money'], $result_expect['saved_money'],0.02);
        $this->assertEquals(($result['user_coupon_record'])->id, ($result_expect['user_coupon_record'])->id);

    }



    /**
     * 返回一张满减固定额的优惠券。
     *
     * @return void
     */
    public function test_find_user_coupon_from_shopping_cart_return_fix_right()
    {
        $service = new ServiceOrder();

        //设置购物车
        $shopping_carts = $this->set_datas_to_shopping_carts();
        $shopping_carts = $this->json_change($shopping_carts);

        // 设置商品数据。 总价 30+ 20 + 60 = 110
        $goods_records = $this->set_goods_records();
        $goods_records = $this->json_change($goods_records);

        // 40元那个,优惠最大,应该返回id=2记录。
        $user_coupon_records = [
            [
                'id' => 1,
                'type' => 1,
                'coupon_value' => 800,
                'coupon_name' => '优惠券1',
                'condition_money' => 1000,
                'use_status' =>0,
            ],
            [
                'id' => 2,
                'type' => 1,
                'coupon_value' => 40,
                'coupon_name' => '优惠券2',
                'condition_money' => 50,
                'use_status' =>0,
            ],
            [
                'id' => 4,
                'type' => 2,
                'coupon_value' => 0.9,
                'coupon_name' => '优惠券4',
                'condition_money' => 50,
                'use_status' =>0,
            ],
            [
                'id' => 5,
                'type' => 1,
                'coupon_value' => 6,
                'coupon_name' => '优惠券5',
                'condition_money' => 50,
                'use_status' =>0,
            ],

        ];
        $user_coupon_records = $this->json_change($user_coupon_records);

        $result = $service->find_user_coupon_from_shopping_cart( $shopping_carts, collect($goods_records),
            collect($user_coupon_records ) );

        $result_expect = [
            'saved_money' =>40,
            'user_coupon_record'=>(object)[
                'id' => 2,
                'type' => 1,
                'coupon_value' =>40,
                'condition_money' => 50,
            ],
        ];
        $this->assertEqualsWithDelta($result['saved_money'], $result_expect['saved_money'],0.02);
        $this->assertEquals(($result['user_coupon_record'])->id, ($result_expect['user_coupon_record'])->id);

    }



    /**
     * 用户没有优惠券的情况。
     *
     * @return void
     */
    public function test_find_user_coupon_from_shopping_cart_when_no_coupon_return_0()
    {
        $service = new ServiceOrder();

        //设置购物车
        $shopping_carts = $this->set_datas_to_shopping_carts();
        $shopping_carts = $this->json_change($shopping_carts);

        // 设置商品数据。 总价 30+ 20 + 60 = 110
        $goods_records = $this->set_goods_records();
        $goods_records = $this->json_change($goods_records);

        // 110的一折是 11元,优惠最大,应该返回id=4记录。
        $user_coupon_records = [];
        $user_coupon_records = $this->json_change($user_coupon_records);

        $result = $service->find_user_coupon_from_shopping_cart( $shopping_carts, collect($goods_records),
            collect($user_coupon_records ) );

        $result_expect = [
            'saved_money' =>0,
            'user_coupon_record'=>null
        ];
        $this->assertEquals($result['saved_money'], $result_expect['saved_money']);
        $this->assertNull($result['user_coupon_record']);

    }


    /**
     * 用户有优惠券的情况,但没有满足限制条件总价,所以应该一张优惠券都不给。
     *
     * @return void
     */
    public function test_find_user_coupon_from_shopping_cart_when_no_coupon_meeting_the_conditions_return_0()
    {
        $service = new ServiceOrder();

        //设置购物车
        $shopping_carts = $this->set_datas_to_shopping_carts();
        $shopping_carts = $this->json_change($shopping_carts);

        // 设置商品数据。 总价 30+ 20 + 60 = 110
        $goods_records = $this->set_goods_records();
        $goods_records = $this->json_change($goods_records);

        // 用户有优惠券,但条件太高,满足不了。
        $user_coupon_records = [
            [
                'id' => 1,
                'type' => 1,
                'coupon_value' => 5,
                'coupon_name' => '优惠券1',
                'condition_money' => 1000,
                'use_status' =>0,
            ],
            [
                'id' => 2,
                'type' => 1,
                'coupon_value' => 5,
                'coupon_name' => '优惠券2',
                'condition_money' => 2000,
                'use_status' =>0,
            ],
        ];
        $user_coupon_records = $this->json_change($user_coupon_records);

        $result = $service->find_user_coupon_from_shopping_cart( $shopping_carts, collect($goods_records),
            collect($user_coupon_records ) );

        $result_expect = [
            'saved_money' =>0,
            'user_coupon_record'=>null
        ];
        $this->assertEquals($result['saved_money'], $result_expect['saved_money']);
        $this->assertNull($result['user_coupon_record']);

    }


}
集成测试代码
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\DatabaseTestCase;
use Tests\TestCase;

class OrderControllerTest extends DatabaseTestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->postJson('/api/find_user_coupon', [
            'user_id' =>1,
            'shopping_cart'=>[
                [
                    'goods_id' => 1,
                    'count' => 3,
                ],
                [
                    'goods_id' => 2,
                    'count' => 1,
                ],
                [
                    'goods_id' => 3,
                    'count' => 2,
                ],
            ],
        ]);

        $response->assertStatus(200);
        $data = $response->getContent();
        $data = json_decode($data,1);
        $result = $data['data'];

        $result_expect = [
            'saved_money' =>11,
            'user_coupon_record'=>[
                'id' => 4,
                'type' => 2,
                'coupon_value' => 0.9,
                'condition_money' => 50,
            ],
        ];
        $this->assertEqualsWithDelta($result['saved_money'], $result_expect['saved_money'],0.02);
        $this->assertEquals($result['user_coupon_record']['id'], $result_expect['user_coupon_record']['id']);



    }

    public function get_table_datas()
    {
        return <<<sql
goods:
  -
    id: 1
    goods_name: "商品1"
    price: 10
  -
    id: 2
    goods_name: "商品2"
    price: 20
  -
    id: 3
    goods_name: "商品3"
    price: 30

user_coupons:
  -
    id: 1
    type: 1
    coupon_value: 5
    coupon_name: "优惠券1"
    condition_money: 1000
    use_status: 0
    user_id: 1
  -
    id: 2
    type: 1
    coupon_value: 5
    coupon_name: "优惠券2"
    condition_money: 50
    use_status: 0
    user_id: 1    
  -
    id: 4
    type: 2
    coupon_value: 0.9
    coupon_name: "优惠券4"
    condition_money: 50
    use_status: 0
    user_id: 1    
  -
    id: 5
    type: 1
    coupon_value: 6
    coupon_name: "优惠券5"
    condition_money: 50
    use_status: 0
    user_id: 1    

sql;

    }
}
购物车对象
<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2022/9/23
 * Time: 13:14
 */
namespace App\Services\Order;
use Exception;

/**
 * 购物车参数对象,与数据库无关。
 *
 * Class ShoppingCart
 * @package App\Services\Order
 */
class ShoppingCart
{
    public $goods_id;
    public $count;

    public function __construct($goods_id, $count)
    {
        if (!$goods_id) {
            throw new Exception('入参商品id错误');
        }
        $count = intval($count);

        if (!$count) {
            throw new Exception('入参商品数量错误');
        }
        $this->goods_id=$goods_id;
        $this->count=$count;
    }
}
控制器
<?php

namespace App\Http\Controllers\Order;

use App\Http\Controllers\Controller;
use App\Services\Order\ServiceOrder;
use App\Services\Order\ShoppingCart;
use App\Services\Stub;
use Illuminate\Http\Request;

class OrderController extends Controller
{
    /**
     * 查找优惠券。
     *
     * @param Request $request
     * @param ServiceOrder $serviceOrder
     * @return \Illuminate\Http\JsonResponse
     */
    public function find_user_coupon(Request $request, ServiceOrder $serviceOrder)
    {
        $input_user_id = $request->input('user_id');
        $input_shopping_carts = $request->input('shopping_cart');
        $shopping_carts = [];
        foreach ($input_shopping_carts as $input_shopping_cart) {
            $shopping_carts []= new ShoppingCart($input_shopping_cart['goods_id'], $input_shopping_cart['count'] );
        }

        $user_coupon_record = $serviceOrder->controller_find_user_coupon($input_user_id, $shopping_carts);

        $data =[
           'code' =>0,
           'data' =>  $user_coupon_record,
        ];
        return response()->json($data)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }
}
核心 service
<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2022/9/23
 * Time: 13:14
 */
namespace App\Services\Order;


use App\Models\Goods;
use App\Models\UserCoupon;
use Illuminate\Support\Collection;

class ServiceOrder
{
    /*
     * 查找优惠券。
     *
     * @param $input_user_id
     * @param $input_shopping_carts array 购物车格式
     *         [
     *            [
     *                'goods_id' => 1,
     *                'count' => 3,
     *            ],
     *            ... ...
     *        ];
     *
     * @throws \Exception
     */
    public function controller_find_user_coupon($input_user_id,$shopping_carts )
    {
        // 用户持有的优惠券。
        $user_coupon_records = UserCoupon::query()
            ->where('user_id', $input_user_id)
            ->where('use_status', 0)
            ->get();

        //根据购物车查商品。
        $goods_records =collect([]);
        foreach ( $shopping_carts as $shopping_cart ){
            $goods_records->push( Goods::findOrFail($shopping_cart->goods_id) );
        }

        //根据购物车内容,及查出的商品价格,还有用户已有的优惠券。去查找最优的优惠券。
        $user_coupon_record = $this->find_user_coupon_from_shopping_cart(
            $shopping_carts, $goods_records ,$user_coupon_records
        );
        return $user_coupon_record;

    }


    /*
     * 根据购物车信息,和已有的优惠券,查找最优惠的一张优惠券。
     *
     * @param array $shopping_cart 前端传来的商品信息。
     * // 购物车格式
     * $shopping_cart = [
     *            [
     *                'goods_id' => 1,
     *                'count' => 3,
     *            ],
     *            ... ...
     *        ];
     *
     * @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_carts,Collection $goods_records,
                                                        Collection $user_coupon_records):array
    {
        $total = $this->calculate_total_price( $shopping_carts, $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' => $finded_user_coupon,
              ];
        }
        return [
            'saved_money' => 0,
            'user_coupon_record' => null,
        ];
    }


    /**
     * 计算购物车总价。
     *
     * @param array $shopping_cart
     * @param Collection $goods_records
     * @return float
     * @throws \Exception
     */
    private function calculate_total_price(array $shopping_carts,Collection $goods_records):float
    {
        $total=0;
        foreach( $shopping_carts as $shopping_cart){
            $count = $shopping_cart->count;
            $unit_price=0;
            foreach ( $goods_records as $goods ){
                if ( $goods->id == $shopping_cart->goods_id ){
                    $unit_price = $goods->price;
                    break;
                }
            }
            if (!$unit_price) {
                throw new \Exception('参数错误');
            }
            $total += $count * $unit_price;
        }
        return $total;
    }
}

总结:

1、假设了4种获得优惠券的情况,都放在速度极快的单元测试代码中完成,耗时的集成测试只放了一种情况,十分完美。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
49
粉丝
7
喜欢
60
收藏
94
排名:592
访问:1.3 万
私信
所有博文
社区赞助商