3.05 路由树-静态匹配之路由查找
PART1. 定义查找路由的方法
所谓查找路由,就是根据给定的HTTP动词和uri,在路由树中查找对应的节点.
router.go:
// findRoute 根据给定的HTTP方法和路由路径,在路由森林中查找对应的节点
func (r *router) findRoute(method string, path string) (*node, bool) {
// 沿着树深度遍历
}注:此处也没有把全部router.go的代码放进来,因为太乱了,只放了和本小节有关的部分
PART2. 定义测试用例
2.1 在测试函数中注册路由
这一部分和注册路由的测试用例代码完全相同
router_test.go:
// TestNode 测试路由树节点
// 由于此处我们要测试的是路由树的结构,因此不需要在测试路由树节点中添加路由处理函数
// 调用addRoute时写死一个HandleFunc即可
type TestNode struct {
method string
path string
}
// TestRouter_findRoute 测试路由查找功能
func TestRouter_findRoute(t *testing.T) {
// step1. 构造路由树
testRoutes := []TestNode{}
r := newRouter()
mockHandleFunc := func(ctx Context) {}
for _, testRoute := range testRoutes {
r.addRoute(testRoute.method, testRoute.path, mockHandleFunc)
}
}2.2 构造测试用例
2.2.1 定义测试用例的类型
这里我们需要通过这个类型知道如下信息:
在给定的HTTP动词和uri的前提下,是否在路由树中找到了节点?
在给定的HTTP动词和uri的前提下,找到的节点和预定义的节点是否相同?
router_test.go:
2.2.2 定义测试的过程
step1. 判断是否在路由树中找到节点
step2. 判断找到的节点和预定义的节点是否相同
这里需要注意的是,和之前写
addRoute()方法的测试用例相同,不能用assert.Equal()方法直接比对两个node结构体的实例,因为HandleFunc不可比
router_test.go:
2.2.3 构造测试用例
所谓构造测试用例,就是要考虑findRoute()方法会遇到什么场景(或者也可以说遇到什么边缘条件):
HTTP动词不存在
完全命中
命中了但找到的node中,handler是nil
根节点
没有找到path
PART3. 以TDD的方式开发findRoute()方法
findRoute()方法3.1 HTTP动词不存在的情况
3.1.1 实现
这个case比较简单,当给定的HTTP动词不存在时,直接返回nil, false即可:
router.go:
3.1.2 测试
router_test.go:
注:这里把testCases的类型改成了匿名结构体,不然没法用IDE的单个测试功能.单个测试功能如下图示:

3.2 完全命中的情况
3.2.1 实现
step1. 切割path
切割
path时注意前导/和后置/
step2. 从根节点开始按"层次"(切割
path后的字符串切片其实每个元素就是"一层")找子节点,找到了则继续深入一层step3. 没找到就返回
nil, false即可
router.go:
node.go:(此处只写新增的方法)
3.2.2 测试
router_test.go:
3.3 命中了,但找到的node中,handler是nil的情况
这个case只需要加一个测试用例即可,因为按照我们设计的findRoute(),在返回时并没有关注HandleFunc是否为nil
router_test.go:
3.4 根节点
3.4.1 测试
router_test.go:

3.4.2 修bug



可以看到,过滤掉/之后,切割path的结果不符合预期.
修复思路:对根节点做特殊处理
router.go:
3.5 没有找到path
这里也是先加测试用例,发现能通过,就可以了.
router_test.go
附录
TODO:要去看v2代码中的用例,然后再拿回来跑
Last updated