本章节仅对开发package的项目有参考价值,业务项目开发代码示例的意义不大。

Golang采用了package包设计的概念,对于包所有导出的包方法以及类型方法都应当有代码示例,代码示例不仅仅是作为包使用的示例,更是单元测试的补充。换句话来讲,你开发的包不仅仅是自己知道怎么使用,更需要通过代码示例告诉团队的其他成员如何使用你开发的包,并且可以通过提高单元测试覆盖率来进一步完善包的代码质量。

代码示例的单元测试覆盖率只能作为单元测试的一个补充,因为代码示例能够实现的单元测试功能比较简单。

文件名称

代码示例的文件放置于包目录中,文件名称一般使用_example_test.go作为文件名后缀,这也是标准库的命名方式。在GoFrame框架的代码中,同一个包下往往存在多个测试文件,代码示例文件的规则一般使用包名_example_test.go文件,并且代码示例文件也可以存在多个,例如:gset_example_any_test.go, gset_example_str_test.go, gset_example_int_test.go用于区分内部不同类型方法的示例。

GoFrame源码文件中有时为了文件排序更优雅,往往会在测试文件命名中加上z的字符便于将所有的测试文件排序到所有包文件末尾,例如:gset_z_example_any_test

代码格式

包方法

如果是导出的包方法示例,那么示例方法定义为:

func ExampleXXX() {
    // ...
}

其中XXX表示示例的包方法。

类型方法

如果是导出的类型方法示例,那么示例方法定义为:

func ExampleYYY_XXX() {
    // ...
}

其中YYY表示类型名称,XXX表示该类型对应的方法。

示例展示

为了能更好地阐述,我们这里以gset包为例,代码示例文件内容的格式如下:

package gset_test

import (
	"fmt"
	"github.com/gogf/gf/v2/container/gset"
	"github.com/gogf/gf/v2/frame/g"
)

func ExampleSet_IsSubsetOf() {
	var s1, s2 gset.Set
	s1.Add(g.Slice{1, 2, 3}...)
	s2.Add(g.Slice{2, 3}...)
	fmt.Println(s1.IsSubsetOf(&s2))
	fmt.Println(s2.IsSubsetOf(&s1))

	// Output:
	// false
	// true
}

其中ExampleSet_IsSubsetOfSet表示该示例针对gset包中的Set类型,IsSubsetOf表示示例的是Set类型的IsSubsetOf方法使用。

Output断言注释

在代码示例中,Output断言注释是非常重要的,在Output后面的注释都是该示例在执行后的输出内容断言。Output断言注释的存在也将该代码示例作为单元测试的额外补充,提高代码覆盖率。

Output断言注释非必需,但很有必要,我们推荐所有的代码示例方法都加上该注释。如果没有Output断言注释,或者该示例无法断言,那么该代码示例方法仅仅是作为一个示例展示,没有更多的意义。

我们统一约定注释后保留1个空格,以便注释内容的展示统一和优雅。

Output断言注释存在时,Goland会自动识别该方法可直接运行,方法左侧出现运行图标:


示例展示

代码示例写完后,如果是带有Output断言注释的方法将会在go test单元测试运行时同时运行该示例代码并执行对应的断言判断。如果是单纯的代码示例,将会展示在Godoc文档上,并且在Goland的代码提示中也会带有该代码示例。

我们仍然使用gset包来举例。

Godoc代码示例

https://pkg.go.dev/github.com/gogf/gf/v2/container/gset#Set.IsSubsetOf

Goland代码提示

鼠标移动到指定方法上即刻便有悬浮代码提示框:





Content Menu

  • Címkék nélkül

7 megjegyzés

  1. ' Yufan Sheng' típus

    这个注释方式第一次见到,是 Golang 语言原生就有的方法么?

  2. ' 东子' típus

    Output断言注释 


    这一段我找到该文件可是并没有运行调试的三角符号,另外这个断言注释是怎么添加的呢,没找到有说明

    1. ' Jeyrce' típus

      没有运行三角符号说明你的IDE可能不支持,断言注释本质还是注释,因此你可以自己运行处出来的结果粘贴到此,然后添加注释前缀,并不是自动生成的

  3. ' Tommy' típus

    Output断言注释确实可以给开发调试带来很多便利。

  4. ' 杨佳佳' típus

    exception recovered: implement not found for interface IUser, forgot register?这个问题怎么解决


    var (
    localUser IUser
    )

    func User() IUser {
    if localUser == nil {
    panic("implement not found for interface IUser, forgot register?")
    }
    return localUser
    }

    func RegisterUser(i IUser) {
    localUser = i
    }




    type (
    sUser struct{}
    )

    func init() {
    service.RegisterUser(New())
    }

    func New() service.IUser {
    return &sUser{}
    }
    1. ' Liam' típus

      +1 遇到同样的问题