2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Es wird empfohlen, zuerst zu lesen: https://blog.csdn.net/a18792721831/article/details/140062769
Go-Knowledge-Test-Arbeitsmechanismus
Der Beispieltest muss sicherstellen, dass die Testdatei mit endet_test.go
Ende.
Die Testmethode muss seinExampleXxx
Anfang.
Testdateien können im selben Verzeichnis wie der Quellcode oder in einem separaten Verzeichnis liegen.
Einzeiliges Ausgabeformat erkennen als // Ausgabe: <erwartete Zeichenfolge>
Das Erkennungsformat der mehrzeiligen Ausgabe ist // Ausgabe: n <erwartete Zeichenfolge> n <erwartete Zeichenfolge> n, jede erwartete Zeichenfolge belegt eine Zeile
Das Format zum Erkennen einer ungeordneten Ausgabe ist // Ungeordnete Ausgabe: n <erwartete Zeichenfolge> n <erwartete Zeichenfolge> n <erwartete Zeichenfolge>, jede erwartete Zeichenfolge belegt eine Zeile
Die Testzeichenfolge ignoriert automatisch Leerzeichen vor und nach der Zeichenfolge.
Wenn in der Testfunktion keine Ausgabedarstellung vorhanden ist, wird die Testfunktion nicht ausgeführt.
In der Zeichenfolgenausgabe kann es sich um eine Zeile, mehrere Zeilen oder eine falsche Reihenfolge handeln.
Die Funktion ist wie folgt:
func Hello() {
fmt.Println("Hello")
}
func HelloTwo() {
fmt.Println("Hello")
fmt.Println("hi")
}
func HelloMore() {
m := make(map[string]string)
m["hello"] = "Hello"
m["hi"] = "hi"
m["你好"] = "你好"
for _, v := range m {
fmt.Println(v)
}
}
Dann nutzen Sie den Beispieltest
func ExampleHello() {
Hello()
// Output: Hello
}
func ExampleHelloTwo() {
HelloTwo()
// Output:
// Hello
// hi
}
func ExampleHelloMore() {
HelloMore()
// Unordered output:
// Hello
// hi
// 你好
}
verwendengo test -v
Führen Sie Beispieltests aus. -v gibt die Ergebnisse der Konsolenausgabe an
Jeder Test verfügt über eine Datenstruktur, um ihn nach der Kompilierung zu übertragen. Für den Beispieltest ist es InternalExample:
type InternalExample struct {
Name string // 测试名称
F func() // 测试函数
Output string // 期望字符串
Unordered bool // 输出是否无序
}
Zum Beispiel der folgende Fall:
func ExampleHelloMore() {
HelloMore()
// Unordered output:
// Hello
// hi
// 你好
}
Nach der Kompilierung die Datenstrukturmitglieder
InternalExample.Name = "ExampleHelloMore"
InternalExample.F = ExampleHelloMore()
InternalExample.Output = "hellonhin你好n"
InternalExample.Unordered = true
Im Artikel: Go-Knowledge-Test-Arbeitsmechanismus
Wir wissen, dass es beim Kompilieren aufgerufen wirdsrc/cmd/go/internal/load/test.go:528
Unter Last werden vier Arten von Tests separat verarbeitet: Komponententest, Leistungstest, Haupttest und Beispieltest.
Überprüfen Sie beim Verarbeiten der Testdatei, ob der Kommentar eine Ausgabe enthält
Und kapseln Sie Metadaten
Nachdem die Metadaten gekapselt wurden, werden die Metadaten verwendet, um die Vorlage zu rendern, den Haupteintrag zu generieren und gleichzeitig das InternalExample-Slice zu rendern.
Wenn es ausgeführt wird, wird es ausgeführttesting.M.Run
, wird in Run ausgeführtrunExamples
func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
ok = true
var eg InternalExample
// 对每个实例测试进行执行
for _, eg = range examples {
// 是否匹配
matched, err := matchString(*match, eg.Name)
if err != nil {
fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %sn", err)
os.Exit(1)
}
if !matched {
continue
}
ran = true
// 执行
if !runExample(eg) {
ok = false
}
}
return ran, ok
}
func runExample(eg InternalExample) (ok bool) {
// 附加输出
if *chatty {
fmt.Printf("=== RUN %sn", eg.Name)
}
// 获取标准输出
stdout := os.Stdout
// 新建管道,将标准输出拷贝一份
r, w, err := os.Pipe()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
os.Stdout = w
// 创建一个管道,用于接收标准输出返回的字符串
outC := make(chan string)
// 在一个单独的 goroutine 中处理拷贝的输出
go func() {
var buf strings.Builder
_, err := io.Copy(&buf, r)
r.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "testing: copying pipe: %vn", err)
os.Exit(1)
}
outC <- buf.String()
}()
finished := false
start := time.Now()
// 在延迟函数中,读取管道中的数据
defer func() {
timeSpent := time.Since(start)
w.Close()
os.Stdout = stdout
// 获取标准输出
out := <-outC
err := recover()
// 调用 processRunResult 进行比较
ok = eg.processRunResult(out, timeSpent, finished, err)
}()
// 执行示例函数,也就是目标函数
eg.F()
finished = true
return
}
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered interface{}) (passed bool) {
passed = true
dstr := fmtDuration(timeSpent)
var fail string
// 标准输出,去除空字符,这也是为何实例测试中会忽略空白字符
got := strings.TrimSpace(stdout)
// 期望输出
want := strings.TrimSpace(eg.Output)
// 是否乱序
if eg.Unordered {
// 先排序,然后字符串比较
if sortLines(got) != sortLines(want) && recovered == nil {
fail = fmt.Sprintf("got:n%snwant (unordered):n%sn", stdout, eg.Output)
}
} else {
if got != want && recovered == nil {
fail = fmt.Sprintf("got:n%snwant:n%sn", got, want)
}
}
if fail != "" || !finished || recovered != nil {
fmt.Printf("--- FAIL: %s (%s)n%s", eg.Name, dstr, fail)
passed = false
} else if *chatty {
fmt.Printf("--- PASS: %s (%s)n", eg.Name, dstr)
}
if recovered != nil {
// Propagate the previously recovered result, by panicking.
panic(recovered)
}
if !finished && recovered == nil {
panic(errNilPanicOrGoexit)
}
return
}