栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

Golang-单元测试

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Golang-单元测试

单元测试

针对使用传统方式测试代码块的不足:
1)测试代码块需要在main函数中去调用,需要修改main函数,若项目正在运行,就可能去停止项目,不方便
2)不利于管理,当需要测试多个函数或多个模块时,都需要在main函数,不利于我们管理和清晰思路
3)引出单元测试。testing测试框架,很好解决上述问题。

1. 基本介绍

Go语言自带有一个轻量级的测试框架testing和自带的 go test命令实现单元测试和性能测试。testing框架和其它语言中的测试框架类似,可以基于这个框架写针对相应函数的测试用例,也可以基于该框架写相应的压力测试用例。通过单元测试,可以解决:
1)确保每个函数的是可运行,并且运行结果是正确的
2)确保代码的性能是好的
3)单元测试能及时的发现程序设计或实现的逻辑错误,使得问题及时暴露,便于问题的定位和解决;而性能测试的重点在于发现程序设计上的问题,确保程序在高并发的情况下还能保持稳定。

2.单元测试入门案例

Golang中提供了testing包,该包提供对Go包的自动化测试的支持。通过go test命令能够自动执行如下形式的任何函数:

func TestXxx(*testing.T)

  1. 其中 Xxx 可以是任何字母数字字符串(但第一个字母不能是 [a-z],且必须大写),用于识别测试程序。
    2.要编写一个新的测试套件,需要创建一个名称以 _test.go 结尾的文件,该文件包含 TestXxx 函数,如上所述。 将该文件放在与被测试的包相同的包中。该文件将被排除在正常的程序包之外,但在运 行 “go test” 命令时将被包含。

测试原理图:

入门案例:
使用到testing包中的func (*T) Logf与func (*T) Fatalf。

func (*T) Logf
func (c *T) Logf(format string, args …interface{})
Log 使用与 Printf 相同的格式化语法对它的参数进行格式化,然后将格式化后的文本记录到错误日志里面。
1)对于测试来说,Logf 产生的格式化文本只会在测试失败或者设置了 -test.v 标志的情况下被打印出来;

func (*T) Fatalf
func (c *T) Fatalf(format string, args …interface{})
调用 Fatalf 相当于在调用 Logf 之后调用 FailNow 。

func (*T) FailNow
func (c *T) FailNow()
将当前测试标识为失败并停止执行该测试,在此之后,测试过程将在下一个测试或者下一个基准测试中继续。

案例代码:
被测试函数所在文件cal.go

package cal

func addUpper(num int) int {
	res := 0
	for i := 1; i <= num; i++ {
		res += i
	}
	return res
}

func GetSub(n1, n2 int) int {
	res := n2 - n1//计划是n1-n2 故意写错为n2-n1
	return res
}

测试函数cal_test.go

package cal

import "testing"

// 编写测试案案例,测试addUpper是否正确
func TestAddupper(t *testing.T) {
	// 调用
	res := addUpper(10)
	if res != 55 {
		t.Fatalf("addUpper(10) 执行错误,期望值=%v,实际值=%vn", 55, res)
	}
	// 如果正确,输出日志
	t.Logf("addUpper(10) 执行正确...")
}

func TestGetSub(t *testing.T) {
	res := GetSub(10, 5)
	if res != 5 {
		t.Fatalf("GetSub(10,5) 执行错误,期望值=%v,实际值=%vn", 5, res)
	}
	t.Logf("GetSub(10,5) 执行正确")

}

运行测试指令:
(1)cmd>go test (如果运行正确,无日志,错误时输出日志)
(2)cmd> go test -v (运行正确或错误都输出日志)
(3)PASS表示测试运行成功,FAIL表示测试失败
(4)测试单个文件,需要带上被测试的原文件:go test -v cal_test.go cal.go
(5)测试单个方法:go test -v -run TestAddUpper

Output:
E:goprojectsrcgo_codechapter14testdemo01>go test -v
=== RUN TestAddupper
cal_test.go:13: addUpper(10) 执行正确…
— PASS: TestAddupper (0.00s)
=== RUN TestGetSub
cal_test.go:19: GetSub(10,5) 执行错误,期望值=5,实际值=-5
— FAIL: TestGetSub (0.00s)
FAIL
exit status 1
FAIL go_code/chapter14/testdemo01 0.489s
说明cal.go中GetSub()函数有问题

OutPut
E:goprojectsrcgo_codechapter14testdemo01>go test
— FAIL: TestGetSub (0.00s)
cal_test.go:19: GetSub(10,5) 执行错误,期望值=5,实际值=-5
FAIL
exit status 1
FAIL go_code/chapter14/testdemo01 0.247s
使用go test命令执行,则出现错误才会显示t.Logf()

案例2:
检测josn序列化和反序列化是否正确。
1)使用ioutil.WriteFile()函数将json字符串写入文件

func WriteFile(filename string, data []byte, perm os.FileMode) error
函数向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件,否则在写入数据之前清空文件。因此使用时需谨慎。

2)使用ioutil.ReadFile()函数读取文件中的json信息

func ReadFile(filename string) ([]byte, error)
ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误。

操作代码:
被测文件monster.go

package monster

import (
	"encoding/json"
	"io/ioutil"
	"log"
)

type Monster struct {
	Name  string `json:"name"`
	Age   int    `json:"age,omitempty"`
	Skill string `json:"skill,omitempty"`
}

func (m *Monster) Store() error {
	data, err := json.Marshal(m)
	if err != nil {
		log.Fatal(err)
	}

	// 保存到文件
	filePath := "E:\goproject\src\go_code\chapter14\monster.ser"
	// 将json信息写入文件
	ioutil.WriteFile(filePath, data, 0666)
	return err // nil
}

func (m *Monster) Restore() error {
	// 从文件中获得json信息
	filePath := "E:\goproject\src\go_code\chapter14\monster.ser"
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(data, m)
	if err != nil {
		log.Fatal(err)
	}
	return err
}

测试文件 monster_test.go

package monster

import (
	"testing"
)

var monster = Monster{
	Name:  "红孩儿",
	Age:   1500,
	Skill: "火尖枪",
}

// 测试用例,测试Store方法

func TestStore(t *testing.T) {

	if monster.Store() == nil {
		t.Logf("marshal successfullyn")
	} else {
		t.Logf("marshal fail,err=%vn", monster.Store())
	}
}

// 测试用例,测试Restore方法
func TestRestore(t *testing.T) {
	monster1 := &Monster{}
	if monster1.Restore() != nil {
		t.Logf("unmarshal failn")
	} else {
		if *monster1 == monster {
			t.Logf("Unmarshal successfullyn")
		} else {
			if monster1.Name != monster.Name {
				t.Logf("Unmarshal fail,期望%v, 实际是%vn", monster.Name, monster1.Name)
			}
			if monster1.Age != monster.Age {
				t.Logf("Unmarshal fail,期望%v, 实际是%vn", monster.Age, monster1.Age)
			}
			if monster1.Skill != monster.Skill {
				t.Logf("Unmarshal fail,期望%v, 实际是%vn", monster.Skill, monster1.Skill)
			}

		}

	}

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/993610.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号