4.6 如何测试
类型检查的测试比语法分析稍稍复杂一些,因为首先类型检查要依赖语法分析的输出,其次需要对类型检查器及整个编译环境进行初始化。
可以从check_test.go
文件切入学习现有的测试代码, examples
, fixedbugs
以及testdata
三个目录下包含大量的测试用例,对应的测试入口函数如下:
func TestTestdata(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, 75, "testdata") }
func TestExamples(t *testing.T) { testDir(t, 0, "examples") }
func TestFixedbugs(t *testing.T) { testDir(t, 0, "fixedbugs") }
类型检查器采用的测试策略是黑盒测试,为了能够完成初始化,测试代码中已经实现了很多必要的辅助模块,例如defaultImporter
, 同时语法解析也单独进行了封装。我们可以在check_test.go
自定义如下方法来做测试:
func TestTypecheck(t *testing.T) {
code := `
package p
type A struct {}
func (this *A) name() {}
type B *A
func main() {
var b B
b.name()
}
`
f, err := parseSrc("testTypecheckConst", code)
if err != nil {
panic(err)
}
// Dump 出语法树
syntax.Fdump(os.Stdout, f)
var conf Config
conf.Trace = true
conf.Importer = defaultImporter()
conf.Error = func(err error) {
fmt.Printf("Typecheck Error: %v\n", err)
}
info := Info{
Types: make(map[syntax.Expr]TypeAndValue),
Defs: make(map[*syntax.Name]Object),
Uses: make(map[*syntax.Name]Object),
Selections: make(map[*syntax.SelectorExpr]*Selection),
Implicits: make(map[syntax.Node]Object),
Scopes: make(map[syntax.Node]*Scope),
Inferred: make(map[syntax.Expr]Inferred),
}
conf.Check("<no package>", []*syntax.File{f}, &info)
}
因为设置了conf.Trace = true
, 我们将看到非常详细的检查结果,这里仅仅截取 main 函数的函数体的检查结果作为演示:
== processDelayed == testTypecheckConst:7:23: --- name: func() testTypecheckConst:8:1: --- <end> testTypecheckConst:12:13: --- main: func() testTypecheckConst:13:10: type B testTypecheckConst:13:10: => B (under = *A) // *types2.Named testTypecheckConst:15:7: expr b.name() testTypecheckConst:15:2: . expr b.name testTypecheckConst:15:1: . . expr b testTypecheckConst:15:1: . . => b (variable of type B) testTypecheckConst:15:3: . . ERROR: b.name undefined (type B has no field or method name) Typecheck Error: testTypecheckConst:15:3: b.name undefined (type B has no field or method name) testTypecheckConst:15:2: . => b.name (invalid operand) testTypecheckConst:15:7: => b.name() (invalid operand) testTypecheckConst:16:1: --- <end>
对于方法调用b.name()
, 类型检查器合理地报告了错误。
这样我们就可以任意修改源代码,并通过 UT 的方式查看效果,或者通过调试器查看每个细节是如何工作的了。
最后更新于
这有帮助吗?