15.2 测试-网格测试、基准测试与测试覆盖率

1. 网格测试

函数或方法的输出因收到的输入而异,如果为每个输入专门编写一个测试用例,将导致大量的重复代码。

不妨将输入的各种组合存放在网格之中,只编写一个测试用例即完成对所有输入的测试,比如象下面这样:

var greetingTests = []greetingTest{
        {"en-US", "George",   "Hello George!"},
        {"fr-FR", "Chloé",    "Bonjour Chloé!"},
        {"it-IT", "Giuseppe", "Ciao Giuseppe!"},
}

// 网格测试
// 源代码
// Package greeting return greeting
package greeting
func translate(locale string) string {
    switch locale {
    case "en-US":
        return "Hi "
    case "fr-FR":
        return "Bonjour "
    case "it-IT":
        return "Ciao "
    default:
        return "Hello "
    }
}
// Greeting return greeting
func Greeting(locale, name string) string {
    return translate(locale) + name + "!"
}
// 源代码对应的测试用例(测试输入为我们之前定义的网格)
// 函数或方法的输出因收到的输入而异,如果为每个输入专门编写一个测试用例,将导/// 致大量的重复代码。不妨将输入的各种组合存放在网格之中,只编写一个测试用例即
// 完成对所有输入的测试 
package greeting
import "testing"

type greetingTest struct {
    locale   string
    name     string
    expected string
}

var greetingTests = []greetingTest{
    {"en-US", "George", "Hello George!"},	// 与源代码不一致,会失败
    {"fr-FR", "Chloé", "Bonjour Chloé!"},
    {"it-IT", "Giuseppe", "Ciao Giuseppe!"},
}

func TestGreeting(t *testing.T) {
  for _, test := range greetingTests {
    actual := Greeting(test.locale, test.name)

      if actual != test.expected {
        t.Fatalf(
          "Greeting(%q,%q)->%q, expected %q",
          test.locale, test.name, actual,
          test.expected)
        }
    }
}
// 打印输出:
greeting_test.go:29: Greeting("en-US","George")->"Hi George!", expected "Hello George!"

2. 基准测试

Go语言提供了功能强大的基准测试框架,利用该框架开发人员可以精确地获知,选择何种方式能使程序完成特定任务的性能最优。

基准测试函数的函数名以"Benchmark"开头,接受一个类型为B的参数。

  • func ByPlus(strs ...string) string { ... }
  • func BenchmarkByPlus(b *testing.B) { ... }

在测试函数内部,使用循环反复地调用被测试函数以建立基准。

  • for n := 0; n < b.N; n++ {
            ByPlus("Hello", " ", "World", "!")
    }
  • 循环的次数N无需指定,框架会自动设置它以获得可靠的数据集。(为了避免随机性,会执行N次求平均值来衡量性能)

基准测试结束后,会生成一个测试报告,指出每个被测函数的总调用次数(N)和单次调用的平均耗时(单位ns)。

  • BenchmarkByPlus-8        10000000        185 ns/op

在包目录下执行如下命令,启动基准测试:

  • go test -bench
// 基准测试(测试了3种字符串拼接方法的效率)
// Package joinstrs join strings
package joinstrs 

import (
    "bytes"
    "strings"
)

// ByPlus join strings by plus
func ByPlus(strs ...string) string {
    s := ""
    for _, str := range strs {
        s += str
    }
    return s
}

// ByJoin join strings by join
func ByJoin(strs ...string) string {
    return strings.Join(strs, "")
}

// ByBuff join strings by buffer
func ByBuff(strs ...string) string {
    b := bytes.Buffer{}
    for _, str := range strs {
        b.WriteString(str)
    }
    return b.String()
}

// 基准测试(测试了3种字符串拼接方法的效率)
// 基准测试关注代码的运行性能。基准测试 
// 函数的函数名必须以"Benchmark"开头
// 
// 执行如下命令,启动基准测试: 
// go test -bench .
package joinstrs
import "testing"

func TestByPlus(t *testing.T) {
    // 使用了"testing包"小节所述的actual-expected模式
	 actual, expected := ByPlus(
       "Hello", " ", "World", "!"),
        "Hello World!"
    if actual != expected {
        t.Fatalf("Actual %q, expected %q",
            actual, expected)
    }
}
func TestByJoin(t *testing.T) {
    actual, expected := ByJoin(
        "Hello", " ", "World", "!"),
        "Hello World!"
    if actual != expected {
        t.Fatalf("Actual %q, expected %q",
            actual, expected)
    }
}
func TestByBuff(t *testing.T) {
    actual, expected := ByBuff(
        "Hello", " ", "World", "!"),
        "Hello World!"
    if actual != expected {
        t.Fatalf("Actual %q, expected %q",
            actual, expected)
    }
}
func BenchmarkByPlus(b *testing.B) { // 基准测试
    for n := 0; n < b.N; n++ {
        ByPlus("Hello", " ", "World", "!")
    }
}

func BenchmarkByJoin(b *testing.B) {// 基准测试
    for n := 0; n < b.N; n++ {
        ByJoin("Hello", " ", "World", "!")
    }
}

func BenchmarkByBuff(b *testing.B) {// 基准测试
    for n := 0; n < b.N; n++ {
        ByBuff("Hello", " ", "World", "!")
    }
}
// 打印输出:
 goos: windows
 goarch: amd64
 pkg: test/benchmark
 BenchmarkByPlus-8 10000000 185 ns/op
 BenchmarkByJoin-8 20000000 103 ns/op//字符串拼接strings.Join()是最高效的
 BenchmarkByBuff-8 10000000 161 ns/op
 PASS
 ok       test/benchmark       6.479s

3.测试覆盖率

测试覆盖率指被测试执行的代码总代码百分比。

  • 单元测试通过,说明功能正确
  • 基准测试效果也不错,说明性能可以接受
  • 这并不表示被测软件经受住了考验,因为有些代码可能根本就没有被执行到

在包目录下执行如下命令,计算测试覆盖率:

  • go test -cover
  • 其是针对某一包目录下的所有go源文件中的func进行计算的
// 测试覆盖率指被测试执行的代码占总代码的百分比
// 
// 执行如下命令,启动测试并输出覆盖率: 
// go test -cover
package greeting

import "testing"

func TestGreeting(t *testing.T) {
    actual, expected := Greeting("World"),
        "Hello World!"
    if actual != expected {
        t.Fatalf("Actual %q, expected %q",
            actual, expected)
    }
}
// Package greeting return greeting
package greeting

// Greeting return greeting
func Greeting(s string) string {
    return "Hello " + s + "!"
}

// Farewell return farewell
func Farewell(s string) string {
    return "Goodbye " + s + "!"
}
// 打印输出:
PASS
coverage: 50.0% of statements
ok test/coverage 0.447s 

相关推荐

  1. 15.2 测试-网格测试基准测试测试覆盖率

    2024-06-18 10:00:04       28 阅读
  2. 测试覆盖率那些事

    2024-06-18 10:00:04       41 阅读
  3. 测试用例设计:提升测试覆盖率的策略方法

    2024-06-18 10:00:04       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-18 10:00:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-18 10:00:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-18 10:00:04       82 阅读
  4. Python语言-面向对象

    2024-06-18 10:00:04       91 阅读

热门阅读

  1. WPF 布局控件 Grid表格

    2024-06-18 10:00:04       24 阅读
  2. C++值单例模式与auto_ptr

    2024-06-18 10:00:04       29 阅读
  3. MySQL触发器基本结构

    2024-06-18 10:00:04       31 阅读
  4. 从零开始精通Onvif之图片抓拍

    2024-06-18 10:00:04       29 阅读
  5. PHP之EOF定界符

    2024-06-18 10:00:04       26 阅读
  6. 科研辅助工具

    2024-06-18 10:00:04       25 阅读
  7. Unity与Android交互通信系列(6)

    2024-06-18 10:00:04       27 阅读
  8. idea git stash报错Too many revisions specified

    2024-06-18 10:00:04       31 阅读
  9. 创建单例模式的六种方式

    2024-06-18 10:00:04       33 阅读
  10. jQuery 常用函数解析

    2024-06-18 10:00:04       33 阅读
  11. MVVM模式理解(基于Qt分析)

    2024-06-18 10:00:04       35 阅读