Κοινή χρήση τεχνολογίας

Go-Knowledge Test-Παράδειγμα Test

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Συνιστάται να διαβάσετε πρώτα: https://blog.csdn.net/a18792721831/article/details/140062769

Go-Knowledge Test-Working Mechanism

1. Ορισμός

Το δείγμα δοκιμής πρέπει να διασφαλίζει ότι το αρχείο δοκιμής τελειώνει με_test.goτέλος.
Η μέθοδος δοκιμής πρέπει να είναιExampleXxxαρχή.
Τα δοκιμαστικά αρχεία μπορούν να βρίσκονται στον ίδιο κατάλογο με τον πηγαίο κώδικα ή σε ξεχωριστό κατάλογο.
Ανίχνευση μορφής εξόδου μιας γραμμής ως // Έξοδος: <αναμενόμενη συμβολοσειρά>
Η μορφή ανίχνευσης της εξόδου πολλαπλών γραμμών είναι // Έξοδος: n <αναμενόμενη συμβολοσειρά> n <αναμενόμενη συμβολοσειρά> n, κάθε αναμενόμενη συμβολοσειρά καταλαμβάνει μία γραμμή
Η μορφή ανίχνευσης μη διατεταγμένης εξόδου είναι // Unordered output: n <αναμενόμενη συμβολοσειρά> n <αναμενόμενη συμβολοσειρά> n <αναμενόμενη συμβολοσειρά>, κάθε αναμενόμενη συμβολοσειρά καταλαμβάνει μία γραμμή
Η δοκιμαστική συμβολοσειρά θα αγνοήσει αυτόματα τους χαρακτήρες κενού διαστήματος πριν και μετά τη συμβολοσειρά.
Εάν δεν υπάρχει αναπαράσταση εξόδου στη συνάρτηση δοκιμής, η συνάρτηση δοκιμής δεν θα εκτελεστεί.

2. Παράδειγμα

Στην έξοδο συμβολοσειράς, μπορεί να είναι μία γραμμή, μπορεί να είναι πολλές γραμμές ή μπορεί να είναι εκτός λειτουργίας.
Η λειτουργία είναι η εξής:

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)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Στη συνέχεια χρησιμοποιήστε το παράδειγμα δοκιμής

func ExampleHello() {
	Hello()
	// Output: Hello
}

func ExampleHelloTwo() {
	HelloTwo()
	// Output:
	// Hello
	// hi
}

func ExampleHelloMore() {
	HelloMore()
	// Unordered output:
	// Hello
	// hi
	// 你好
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

χρήσηgo test -v Εκτελέστε δειγματοληπτικές δοκιμές, το -v υποδεικνύει αποτελέσματα εξόδου κονσόλας
Εισαγάγετε την περιγραφή της εικόνας εδώ

3. Δομή δεδομένων

Κάθε δοκιμή έχει μια δομή δεδομένων για τη μεταφορά του μετά τη μεταγλώττιση Για το παράδειγμα δοκιμής, είναι το InternalExample:

type InternalExample struct {
	Name      string // 测试名称
	F         func() // 测试函数
	Output    string // 期望字符串
	Unordered bool // 输出是否无序
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Για παράδειγμα, η ακόλουθη περίπτωση:

func ExampleHelloMore() {
	HelloMore()
	// Unordered output:
	// Hello
	// hi
	// 你好
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Μετά τη συλλογή, τα μέλη της δομής δεδομένων

InternalExample.Name = "ExampleHelloMore"
InternalExample.F = ExampleHelloMore()
InternalExample.Output = "hellonhin你好n"
InternalExample.Unordered = true
  • 1
  • 2
  • 3
  • 4

4. Διαδικασία σύνταξης

Στο άρθρο: Go-Knowledge Test-Working Mechanism

Go-Knowledge Test-Working Mechanism

, ξέρουμε ότι κατά τη μεταγλώττιση, θα καλείταιsrc/cmd/go/internal/load/test.go:528
Εισαγάγετε την περιγραφή της εικόνας εδώ

Στο φορτίο, τέσσερις τύποι δοκιμών θα υποβληθούν σε επεξεργασία ξεχωριστά: δοκιμή μονάδας, δοκιμή απόδοσης, κύρια δοκιμή και δοκιμή δείγματος.
Εισαγάγετε την περιγραφή της εικόνας εδώ

Κατά την επεξεργασία του αρχείου δοκιμής, ελέγξτε εάν το σχόλιο περιέχει έξοδο
Εισαγάγετε την περιγραφή της εικόνας εδώ

Και ενσωματώστε τα μεταδεδομένα
Εισαγάγετε την περιγραφή της εικόνας εδώ

Αφού ενθυλακωθούν τα μεταδεδομένα, τα μεταδεδομένα θα χρησιμοποιηθούν για την απόδοση του προτύπου, τη δημιουργία της κύριας καταχώρισης και την απόδοση του τμήματος InternalExample ταυτόχρονα.
Εισαγάγετε την περιγραφή της εικόνας εδώ

5. Διαδικασία εκτέλεσης

Όταν εκτελεστεί, θα εκτελεστεί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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34