Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Se recomienda leer primero: https://blog.csdn.net/a18792721831/article/details/140062769
Mecanismo de trabajo de prueba de conocimiento
La prueba de muestra debe garantizar que el archivo de prueba termine con_test.go
fin.
El método de prueba debe serExampleXxx
comienzo.
Los archivos de prueba pueden estar en el mismo directorio que el código fuente o en un directorio separado.
Detectar formato de salida de una sola línea como // Salida: <cadena esperada>
El formato para detectar salida de varias líneas es // Salida: n <cadena esperada> n <cadena esperada> n, cada cadena esperada ocupa una línea
El formato para detectar resultados desordenados es // Salida desordenada: n <cadena esperada> n <cadena esperada> n <cadena esperada>, cada cadena esperada ocupa una línea
La cadena de prueba ignorará automáticamente los espacios en blanco antes y después de la cadena.
Si no hay representación de Salida en la función de prueba, la función de prueba no se ejecutará.
En la salida de la cadena, puede ser una línea, pueden ser varias líneas o puede estar desordenada.
La función es la siguiente:
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)
}
}
Luego use la prueba de ejemplo.
func ExampleHello() {
Hello()
// Output: Hello
}
func ExampleHelloTwo() {
HelloTwo()
// Output:
// Hello
// hi
}
func ExampleHelloMore() {
HelloMore()
// Unordered output:
// Hello
// hi
// 你好
}
usargo test -v
Ejecute pruebas de muestra, -v indica los resultados de salida de la consola
Cada prueba tiene una estructura de datos para transportarla después de la compilación. Para la prueba de ejemplo, es InternalExample:
type InternalExample struct {
Name string // 测试名称
F func() // 测试函数
Output string // 期望字符串
Unordered bool // 输出是否无序
}
Por ejemplo, el siguiente caso:
func ExampleHelloMore() {
HelloMore()
// Unordered output:
// Hello
// hi
// 你好
}
Después de la compilación, los miembros de la estructura de datos.
InternalExample.Name = "ExampleHelloMore"
InternalExample.F = ExampleHelloMore()
InternalExample.Output = "hellonhin你好n"
InternalExample.Unordered = true
En el artículo: Mecanismo de trabajo de prueba de conocimiento
, sabemos que al compilar se llamarásrc/cmd/go/internal/load/test.go:528
En carga, se procesarán cuatro tipos de pruebas por separado: prueba unitaria, prueba de rendimiento, prueba principal y prueba de muestra.
Al procesar el archivo de prueba, verifique si el comentario contiene resultados
Y encapsular metadatos
Una vez encapsulados los metadatos, los metadatos se utilizarán para representar la plantilla, generar la entrada principal y representar el segmento InternalExample al mismo tiempo.
Cuando se ejecute, se ejecutará.testing.M.Run
, se ejecutará en EjecutarrunExamples
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
}