τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Συνιστάται να διαβάσετε πρώτα: https://blog.csdn.net/a18792721831/article/details/140062769
Go-Knowledge Test-Working Mechanism
Το δείγμα δοκιμής πρέπει να διασφαλίζει ότι το αρχείο δοκιμής τελειώνει με_test.go
τέλος.
Η μέθοδος δοκιμής πρέπει να είναιExampleXxx
αρχή.
Τα δοκιμαστικά αρχεία μπορούν να βρίσκονται στον ίδιο κατάλογο με τον πηγαίο κώδικα ή σε ξεχωριστό κατάλογο.
Ανίχνευση μορφής εξόδου μιας γραμμής ως // Έξοδος: <αναμενόμενη συμβολοσειρά>
Η μορφή ανίχνευσης της εξόδου πολλαπλών γραμμών είναι // Έξοδος: n <αναμενόμενη συμβολοσειρά> n <αναμενόμενη συμβολοσειρά> n, κάθε αναμενόμενη συμβολοσειρά καταλαμβάνει μία γραμμή
Η μορφή ανίχνευσης μη διατεταγμένης εξόδου είναι // Unordered output: n <αναμενόμενη συμβολοσειρά> n <αναμενόμενη συμβολοσειρά> n <αναμενόμενη συμβολοσειρά>, κάθε αναμενόμενη συμβολοσειρά καταλαμβάνει μία γραμμή
Η δοκιμαστική συμβολοσειρά θα αγνοήσει αυτόματα τους χαρακτήρες κενού διαστήματος πριν και μετά τη συμβολοσειρά.
Εάν δεν υπάρχει αναπαράσταση εξόδου στη συνάρτηση δοκιμής, η συνάρτηση δοκιμής δεν θα εκτελεστεί.
Στην έξοδο συμβολοσειράς, μπορεί να είναι μία γραμμή, μπορεί να είναι πολλές γραμμές ή μπορεί να είναι εκτός λειτουργίας.
Η λειτουργία είναι η εξής:
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)
}
}
Στη συνέχεια χρησιμοποιήστε το παράδειγμα δοκιμής
func ExampleHello() {
Hello()
// Output: Hello
}
func ExampleHelloTwo() {
HelloTwo()
// Output:
// Hello
// hi
}
func ExampleHelloMore() {
HelloMore()
// Unordered output:
// Hello
// hi
// 你好
}
χρήσηgo test -v
Εκτελέστε δειγματοληπτικές δοκιμές, το -v υποδεικνύει αποτελέσματα εξόδου κονσόλας
Κάθε δοκιμή έχει μια δομή δεδομένων για τη μεταφορά του μετά τη μεταγλώττιση Για το παράδειγμα δοκιμής, είναι το InternalExample:
type InternalExample struct {
Name string // 测试名称
F func() // 测试函数
Output string // 期望字符串
Unordered bool // 输出是否无序
}
Για παράδειγμα, η ακόλουθη περίπτωση:
func ExampleHelloMore() {
HelloMore()
// Unordered output:
// Hello
// hi
// 你好
}
Μετά τη συλλογή, τα μέλη της δομής δεδομένων
InternalExample.Name = "ExampleHelloMore"
InternalExample.F = ExampleHelloMore()
InternalExample.Output = "hellonhin你好n"
InternalExample.Unordered = true
Στο άρθρο: Go-Knowledge Test-Working Mechanism
, ξέρουμε ότι κατά τη μεταγλώττιση, θα καλείταιsrc/cmd/go/internal/load/test.go:528
Στο φορτίο, τέσσερις τύποι δοκιμών θα υποβληθούν σε επεξεργασία ξεχωριστά: δοκιμή μονάδας, δοκιμή απόδοσης, κύρια δοκιμή και δοκιμή δείγματος.
Κατά την επεξεργασία του αρχείου δοκιμής, ελέγξτε εάν το σχόλιο περιέχει έξοδο
Και ενσωματώστε τα μεταδεδομένα
Αφού ενθυλακωθούν τα μεταδεδομένα, τα μεταδεδομένα θα χρησιμοποιηθούν για την απόδοση του προτύπου, τη δημιουργία της κύριας καταχώρισης και την απόδοση του τμήματος InternalExample ταυτόχρονα.
Όταν εκτελεστεί, θα εκτελεστείtesting.M.Run
, θα εκτελεστεί στο RunrunExamples
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
}