教程
总结
在使用 TDD 进行开发时,请牢记以下三项法则:
- 在编写失败的测试之前,不要编写任何业务代码;
- 只要有一个单元测试失败了,就不要再写测试代码。无法通过编译也是一种失败情况;
- 业务代码恰好能够让当前失败的测试成功通过即可,不要多写;
要掌握PHPUnit的用法,如何测试方法,如何测试类,等等…
根据需求结果逆向分析开发的方式。先假设已经实现了需求的方法,然后一步步倒退,缺少什么就创建什么。
需求结果 => 结果方法 => 按需(缺少创建)代码的元素
根据需求准备好测试用例数据
非常适合复杂逻辑需求的推理分析。对于简单的一下就能想出方案的需求,处于节省时间的考虑,可以不用。
测试覆盖率不一定要100%,个人想法,测试要首先覆盖核心复杂、迭代频率较高的主要业务,简单的业务可以跳过。
和普通开发方式一样,首先要对项目的整体需求和完整逻辑有详细了解,要有基本的解决方案思路。
使用渐进式的编码思路,在mvc框架做业务开发时,可以先在控制器方法写出完整的逻辑,即使代码非常多,然后再根据需求迭代使用设计模式或面向对象设计方法,按需要拆分封装成类或方法,完成由面向过程=>面向对象的演变
项目案例说明
要实现一个产品型号搜索候选项功能
需要给前端提供一个http api ,并且要满足各种情景的搜索条件,如图
1.假设这个接口已经存在了,然后创建一个商品接口测试类,写好接口测试方法和各种情境下的测试用例数据。
namespace Tests\Feature;
class GoodsPcApiTest extends TestCase
{
/**
* A basic feature test example.
*
* @return void
*/
public function test_goods_search_option()
{
//只有分隔符
$response = $this->post('/api/goods/search-option', [
'keywords'=>'-',
]);
//使用dump打印结果是为了方便调试,调试完毕可以注释掉
dump('只有分隔符', $response->json());
$response->assertStatus(200);
//只有产品型号
$response = $this->post('/api/goods/search-option', [
'keywords'=>'AC013',
]);
dump('只有产品型号', $response->json());
$response->assertStatus(200);
//产品型号+1分隔符
$response = $this->post('/api/goods/search-option', [
'keywords'=>'AC013-',
]);
dump('产品型号+1分隔符', $response->json());
$response->assertStatus(200);
//产品型号+1分隔符和参数
$response = $this->post('/api/goods/search-option', [
'keywords'=>'AC013-d',
]);
dump('产品型号+1分隔符和1参数', $response->json());
$response->assertStatus(200);
...
}
...
}
然后运行测试,此时测试必然报错,就需要去创建这个接口的控制器和方法以及路由
//路由文件routes/api.php
Route::prefix('goods')->group(function () {
...
Route::post('search-option', [GoodsController::class, 'searchOption']); //搜索候选项
...
});
//控制器
namespace App\Http\Controllers\Api;
class GoodsController extends Controller
{
...
public function searchOption(Request $request)
{
//验证参数
$request->validate([
'keywords'=>'bail|required|string',
]);
//需要根据分隔符-拆分数据
$keywords = $request->input('keywords');
$attribute = array_filter(explode($sep, $keywords));
//要从模型查询,直接调用,如果测试时报错模型不存在就去创建模型
//如果运行测试报错数据表不存在,就创建数据迁移
GoodsParamsSku::select()->where()->get();
//需要一个方法或类来实现某个功能,先调用,然后运行测试,报错functionName方法不存在
$this->functionName()
}
...
}
根据报错创建上述functionName的单元测试
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class xxxxFunctionTest extends TestCase
{
/**
* A basic unit test example.
*
* @return void
*/
public function test_function_name()
{
$this->assertTrue(true);
}
}