go language system - from the file operation unit testing


File Operations

File is a data source (where the save data), such as frequently used word document, txt document, excel file ... is a file. The main role is to save the file data, that is, it can save a picture, you can also keep the video, sound ...

The input and output streams

Form of a stream file is operated in the program

stream: data path between a source data (files) and the program (memory) experienced

Input stream: the data path from a data source (files) to the program (memory)

Output streams: a data path from the program (memory) to the data source (file)

all files related os.File packaging operations, File structure is a

File back operation, often used to structure os.File

Open the file and close the file

Functions and methods of use


Case presentation

import (
   "fmt"
   "os"
)

func main()  {
   //打开文件
   //概念说明:file的叫法
   //1. file 叫 file对象
   //2. file 叫 file指针
   //3. file 叫 file文件句柄
   file, err := os.Open("e:/test.txt")
   if err != nil {
      fmt.Println("Open file err = ", err)
   }
   //输出文件,看看文件是什么,看出file就是一个指针 *Filr
   fmt.Printf("file = %v", file)   //file = &{0xc000070780}
   //关闭
   err = file.Close()
   if err != nil {
      fmt.Println("Close file err = ", err)
   }
}

Read file operation Applications

  1. Reading the contents of the file and displayed on the terminal (band buffer mode), using os.Open, file.Close, bufio.NewReader (), reader.ReadString functions and methods
import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main()  {
	//打开文件
	//概念说明:file的叫法
	//1. file 叫 file对象
	//2. file 叫 file指针
	//3. file 叫 file文件句柄
	file, err := os.Open("E:/gostudent/src/2020-04-02/utils/utils.go")
	if err != nil {
		fmt.Println("Open file err = ", err)
	}
	//当函数退出时,要及时的关闭file
	defer file.Close() //要及时关闭file句柄,否则会有内存泄漏
	//创建一个*Reader , 是带缓冲的
	/*
	   const (
	      defaultBufSize = 4096  //默认的缓冲区为4096
	   )
	*/
	reader := bufio.NewReader(file)
	//循环读取文件的内容
	for {
		str, err := reader.ReadString('\n')  //读到一个换行就结束
		if err == io.EOF {      //io.EOF 表示文件的末尾
			break
		}
		//输出内容
		fmt.Print(str)
	}
	fmt.Println("文件读取结束...")
}
  1. Reading the contents of the file and displayed on the terminal (using ioutil once the entire file is read into memory), this method is applicable to the case of small files. Related methods and functions ioutil.ReadFile
import (
	"fmt"
	"io/ioutil"
)

func main()  {
	//使用ioutil.ReadFile一次性将文件读取到位
	file := "E:/gostudent/src/2020-04-02/utils/utils.go"
	content, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Printf("read file err = %v", err)
	}
	//把读取到的内容显示到终端
	//fmt.Printf("%v", content) //[]byte
	fmt.Printf("%v", string(content)) // []byte
	//这里没有显示的Open文件,因此也不需要显示的Close文件
	//因为,文件的Open和Close被封装到ReadFile函数内部
}

Write file operation Applications

os.OpenFile function

  1. Create a new file, write to: 5 "Hello, zisefeizhu"
import (
	"bufio"
	"fmt"
	"os"
)

func main()  {
	filePath := "E:/gostudent/src/2020-04-05/abc.txt"
	file, err := os.OpenFile(filePath, os.O_CREATE | os.O_WRONLY, 0666)
	if err != nil {
		fmt.Printf("open file err = %v \n", err)
		return
	}
	//及时关闭file句柄
	defer file.Close()
	//准备写入5句: "hello,zisefeizhu"
	str := "hello,zisefeizhu\n" // \n表示换行
	//写入时,使用带缓存的*Writer
	writer := bufio.NewWriter(file)
	for i := 0; i< 5; i++ {
		writer.WriteString(str)
	}
	//因为write是带缓存的,因此在调用WriterString方法时
	//其实内容是先写入到缓存的,所以需要调用Flush方法,将缓冲的数据
	//真正写入到文件中,否则文件中会没有数据!!!
	writer.Flush()
}
  1. Open an existing file, the original content covering the new content into 10 "Hello, Purple Flying Pig"
import (
   "bufio"
   "fmt"
   "os"
)

func main()  {
   //2)打开一个存在的文件,将原来的内容覆盖成新的内容10句“你好,紫色飞猪”
   //1. 打开已经存在的文件E:/gostudent/src/2020-04-05/abc.txt
   filePath := "E:/gostudent/src/2020-04-05/abc.txt"
   file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_TRUNC, 0666)
   if err != nil {
      fmt.Printf("open file err = %v \n", err)
      return
   }
   //及时关闭file句柄
   defer file.Close()
   //准备写入10句: "hello,zisefeizhu"
   str := "你好,紫色飞猪!\n" // \n表示换行
   //写入时,使用带缓存的*Writer
   writer := bufio.NewWriter(file)
   for i := 0; i< 10; i++ {
      writer.WriteString(str)
   }
   //因为write是带缓存的,因此在调用WriterString方法时
   //其实内容是先写入到缓存的,所以需要调用Flush方法,将缓冲的数据
   //真正写入到文件中,否则文件中会没有数据!!!
   writer.Flush()

}
  1. Open an existing file, append the contents of the original "Hello, jingxing"
import (
   "bufio"
   "fmt"
   "os"
)

func main()  {
   //1. 打开已经存在的文件E:/gostudent/src/2020-04-05/abc.txt
   filePath := "E:/gostudent/src/2020-04-05/abc.txt"
   file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_APPEND, 0666)
   if err != nil {
      fmt.Printf("open file err = %v \n", err)
      return
   }
   //及时关闭file句柄
   defer file.Close()
   //追加内容
   str := "你好,jingxing\n" // \n表示换行
   //写入时,使用带缓存的*Writer
   writer := bufio.NewWriter(file)
   for i := 0; i< 10; i++ {
      writer.WriteString(str)
   }
   //因为write是带缓存的,因此在调用WriterString方法时
   //其实内容是先写入到缓存的,所以需要调用Flush方法,将缓冲的数据
   //真正写入到文件中,否则文件中会没有数据!!!
   writer.Flush()
}
  1. Open an existing file, read the original content displayed on the terminal, and an additional 5 "Hello, Shenzhen"
import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main()  {
	//1. 打开已经存在的文件E:/gostudent/src/2020-04-05/abc.txt
	filePath := "E:/gostudent/src/2020-04-05/abc.txt"
	file, err := os.OpenFile(filePath, os.O_RDWR | os.O_APPEND, 0666)
	if err != nil {
		fmt.Printf("open file err = %v \n", err)
		return
	}
	//及时关闭file句柄
	defer file.Close()
	//先读取原来文件的内容,并显示在终端
	reader := bufio.NewReader(file)
	for {
		str, err := reader.ReadString('\n')
		if err == io.EOF {   //如果读取到文件的末尾
			break
		}
		//显示到终端
		fmt.Print(str)
	}
	//追加内容
	str := "你好,深圳\n" // \n表示换行
	//写入时,使用带缓存的*Writer
	writer := bufio.NewWriter(file)
	for i := 0; i< 5; i++ {
		writer.WriteString(str)
	}
	//因为write是带缓存的,因此在调用WriterString方法时
	//其实内容是先写入到缓存的,所以需要调用Flush方法,将缓冲的数据
	//真正写入到文件中,否则文件中会没有数据!!!
	writer.Flush()
}

5) Write a program, the contents of a file, write to another file. Note: These two documents have existed

Note: Use ioutil.ReadFile / ioutil.WriteFile complete the task of writing files

import (
   "fmt"
   "io/ioutil"
)
func main()  {
   //将e:/abc.txt 文件内容导入到e:/abc.txt
   //1. 首先将 e:/abc.txt 内容读取到内存
   //2. 将读取到的内容写入d:/abc.txt
   file1Path := "E:/gostudent/src/2020-04-05/abc.txt"
   file2Path := "D:/abc.txt"
   data, err := ioutil.ReadFile(file1Path)
   if err != nil {
      //说明读取文件有错误
      fmt.Printf("read file err = %v\n", err)
      return
   }
   err = ioutil.WriteFile(file2Path, data, 0666)
   if err != nil {
      fmt.Printf("write file error = %v \n", err)
   }
}

Determine whether a file exists

Go file or folder is determined whether or not there is a method using os.stat () function returns an error value is determined:

  1. If an error is returned to nil, documentation or folder exists

  2. If the wrong type of return used os.IsNotExist () determines true, described the file or folder does not exist

  3. If the return is another type of error, it is uncertain whether there is

File Application Programming examples

Copy files

Description: The picture / movies / mp3 copied to another file e: /abc.jpg

func Copy(dst Writer,src Reader)(written int64, err error)

Note: Copy function is io package provides

import (
   "bufio"
   "fmt"
   "io"
   "os"
)
//编写一个函数,接收两个文件路径 srcFileName dstFileName
func CopyFile(srcFileName string, dstFileName string) (written int64, err error) {
   srcFile, err := os.Open(srcFileName)
   if err != nil {
      fmt.Printf("open file err = %v\n", err)
   }
   defer  srcFile.Close()
   //通过srcfile,获取到Reader
   reader := bufio.NewReader(srcFile)
   //打开dstFileName
   dstFile,err := os.OpenFile(dstFileName, os.O_WRONLY | os.O_CREATE, 0666)
   if err != nil {
      fmt.Printf("open file err = %v\n", err)
      return
   }
   //通过dstFile,获取到Writer
   writer := bufio.NewWriter(dstFile)
   defer  dstFile.Close()
   return io.Copy(writer, reader)
}
func main()  {
   //将d:/abc.jpg 文件拷贝到e:/abc.jpg
   //调用CopyFile 完成文件拷贝
   srcFile := "d:/abc.jpeg"
   dstFile := "e:/abc.jpg"
   _, err := CopyFile(srcFile, dstFile)
   if err == nil {
      fmt.Printf("拷贝完成\n")
   } else {
      fmt.Printf("拷贝错误 err = %v\n", err)
   }
}

English statistics, numbers, spaces, and other number of characters

import (
   "bufio"
   "fmt"
   "io"
   "os"
)
//定义一个结构体,用于保存统计结果
type CharCount struct {
   ChCount int //记录英文个数
   NumCount int //记录数字的个数
   SpaceCount int //记录空格的个数
   OtherCount int //记录其它字符的个数
}

func main()  {
   //思路:打开一个文件,创一个Reader
   //每读取一行,就去统计该行有多少个英文、数字、空格和其它字符
   //然后将结果保存到一个结构体
   fileName := "E:/gostudent/src/2020-04-05/abc.txt"
   file,err := os.Open(fileName)
   if err != nil {
      fmt.Printf("open file err = %v \n", err)
      return
   }
   defer  file.Close()
   //定义个CharCount实例
   var count CharCount
   //创建一个Reader
   reader := bufio.NewReader(file)
   //开始循环读取fleName的内容
   for {
      str, err := reader.ReadString('\n')
      if err == io.EOF { //读到文件末尾就退出
         break
      }
      //为了兼容中文字符,可以将str转成[]rune
      strChange := []rune(str)
      //遍历str,进行统计
      for _,v := range strChange {
         switch  {
         case v >= 'a' && v <= 'z' :
            fallthrough //穿透
         case v >= 'A' && v <= 'Z' :
            count.ChCount++
         case v == ' ' || v == '\t' :
            count.SpaceCount++
         case v >= '0' && v <= '9' :
            count.NumCount++
         default:
            count.OtherCount++
         }
      }
   }
   //输出统计的结果看看是否正确
   fmt.Printf("字符的个数为 = %v 数字的个数为 = %v 空格的个数为 = %v 其它字符个数 = %v",
      count.ChCount, count.NumCount, count.SpaceCount, count.OtherCount)
}

Command line parameters

We are hoping to get to the various parameters of the command line, how to deal with?

os.Args slice is a string, to store all the command line parameters

for example

import (
	"fmt"
	"os"
)

func main()  {
	fmt.Println("命令行的参数有:", len(os.Args))
	//遍历os.Args切片,就可以得到所有的命令行输入参数值
	for i, v := range os.Args {
		fmt.Printf("args[%v] = %v \n", i ,v)
	}
}
//E:\gostudent\src\2020-04-05>go run main.go 999
//命令行的参数有: 2
//args[0] = C:\Users\lxxxxn\AppData\Local\Temp\go-build133979866\b001\exe\main.
//exe
//args[1] = 999

flag packet to parse command line parameters

Explanation: The foregoing embodiment is more native way, it is not particularly convenient for the resolution parameters, in particular in the form of a command line parameter with the specified

For example: cmd> main.exe -fc: /aaa.txtx -p 200 -u root form of such a command line, to provide designers Go flag bag, can easily parse command line parameters, and the order of parameters can be freely

import (
	"flag"
	"fmt"
)

func main()  {
	//定义几个变量,用于接收命令行的参数值
	var user string
	var pwd string
	var host string
	var port int
	//&user就是接收用户命令行中输入的 -u 后面的参数值
	//"u" 就是-u 指定参数
	//" " 默认值
	//"用户名,默认为空" 说明
	flag.StringVar(&user, "u","","用户名,默认为空")
	flag.StringVar(&pwd,"pwd","","密码,默认为空")
	flag.StringVar(&host,"h","localhost","主机名,默认为localhost")
	flag.IntVar(&port,"port",3306,"端口号,默认为3306")
	//有一个非常重要的操作转换,必须调用该方法
	flag.Parse()
	//输出结果
	fmt.Printf("user = %v pwd = %v host = %v port = %v",
		user, pwd, host, port)
}
//E:\gostudent\src\2020-04-05>go run main.go -u root -pwd zisefeizhu -h 20.0.0.201 -port 3306
//user = root pwd = zisefeizhu host = 20.0.0.201 port = 3306

Json

Basic introduction Json

Json (JavaScript Object Notation) is a lightweight data interchange format. Easy to read and write. It is easy for machines to parse and generate. key - val

Json in 2001 to promote the use of data formats, data has become the mainstream format

When the machine is easy to parse and generate Json, and effectively improve network transmission efficiency, usually the program will first data transmission network (structure, map, etc.) into a sequence json string, to the recipient get json string during deserialization of return to the original data type (structure, map, etc.). This has become the standard way of each language

Scenarios

Json Data Format Description

In the JS language, everything is an object. Thus, any data type can be represented by the JSON, such as strings, numbers, objects, array, map, structures and the like

JSON key-value pair is used to store data in a way

Key / value pairs EDITORIAL combination keys and double quotation marks "" package, colon: separated, and then immediately Found:

[{"key1":val1,"key2":val2,"key3":val3,"key4":[val4,val5]},
{"key1":val1,"key2":val2,"key3":val3,"key4":[val4,val5]}]
比如
{"firstName":"Json"}

{"name":"tom","age":18,"address":["北京","上海"]}

[{"name":"zisefeizhu","age":18,"address":["北京","上海"]},
{"name":"jingxing","age":18,"address":["北京","上海"]}]

Jsnon online analytical data

https://www.json.cn/ site can validate a data json format is correct. Especially in the preparation of more complex json format data, useful

Json serialization of

json serialization means, there will be key - the data type of the value structure (such structure, map, slicing) a series string into json

Applications

Demonstrate what structure, map and sequence of the slice, a sequence of data types other similar

import (
   "encoding/json"
   "fmt"
)
//定义一个结构体
type Monster struct {
   Name string
   Age int
   Bithday string
   Sal float64
   Skill string
}

func testStruct()  {
   //演示
   monster := Monster{
      Name : "牛魔王",
      Age : 500,
      Bithday : "2001-11-11",
      Sal : 8000.0,
      Skill : "牛头拳",
   }
   //将monster 序列化
   data, err := json.Marshal(&monster)
   if err != nil {
      fmt.Printf("序列号错误 err = %v \n", err)
   }
   //输出序列化后的结果
   fmt.Printf("monster 序列化后 = %v \n", string(data))
}
//将map进行序列化
func testMap()  {
   //定义一个map
   var a map[string]interface{}
   //使用map,需要先make
   a = make(map[string]interface{})
   a["name"] = "红孩儿"
   a["age"] = 30
   a["address"] = "洪崖洞"
   //将a这个map进行序列化
   data, err := json.Marshal(a)
   if err != nil {
      fmt.Printf("序列号错误 err = %v \n", err)
   }
   //输出序列化后的结果
   fmt.Printf("monster 序列化后 = %v \n", string(data))
}
//演示对切片进行序列化,这个切片[]map[string]interface{}
func testSlice()  {
   var slice []map[string]interface{}
   var m1 map[string]interface{}
   //使用map前,需要先make
   m1 = make(map[string]interface{})
   m1["name"] = "jack"
   m1["age"] = "7"
   m1["address"] = "北京"
   slice = append(slice, m1)

   var m2 map[string]interface{}
   //使用map前,需要先make
   m2 = make(map[string]interface{})
   m2["name"] = "tom"
   m2["age"] = "20"
   m2["address"] = [2]string{"墨西哥","夏威夷"}
   slice = append(slice, m2)
   //将切片进行序列化操作
   data, err := json.Marshal(slice)
   if err != nil {
      fmt.Printf("序列号错误 err = %v \n", err)
   }
   //输出序列化后的结果
   fmt.Printf("monster 序列化后 = %v \n", string(data))
}
//对基本数据类型序列化,意义不大
func testFloat64()  {
   var num1 float64 = 2345.67
   //对num1进行序列化
   data, err := json.Marshal(num1)
   if err != nil {
      fmt.Printf("序列号错误 err = %v \n", err)
   }
   //输出序列化后的结果
   fmt.Printf("monster 序列化后 = %v \n", string(data))
}
func main()  {
   //演示将结构体、map、切片进行序列化
   testStruct()
   testMap()
   testSlice()
   testFloat64()
}
//输出
// monster 序列化后 = {"Name":"牛魔王","Age":500,"Bithday":"2001-11-11","Sal":8000,"Skill":"牛头拳"} 
//monster 序列化后 = {"address":"洪崖洞","age":30,"name":"红孩儿"} 
//monster 序列化后 = [{"address":"北京","age":"7","name":"jack"},{"address":["墨西哥","夏威夷"],"age":"20","name":"tom"}] 
//monster 序列化后 = 2345.67 

Precautions

For serialization structure, the name of the key if you want to be serialized after the re-enactment, you can develop a tag to the struct tag

import (
   "encoding/json"
   "fmt"
)
//定义一个结构体
type Monster struct {
   Name string  `json:"monster_name"` //反射机制 //:两边不要分开
   Age int `json:"monster_age"`
   Bithday string
   Sal float64
   Skill string
}

func testStruct()  {
   //演示
   monster := Monster{
      Name : "牛魔王",
      Age : 500,
      Bithday : "2001-11-11",
      Sal : 8000.0,
      Skill : "牛头拳",
   }
   //将monster 序列化
   data, err := json.Marshal(&monster)
   if err != nil {
      fmt.Printf("序列号错误 err = %v \n", err)
   }
   //输出序列化后的结果
   fmt.Printf("monster 序列化后 = %v \n", string(data))
}
func main()  {
   //演示将结构体、map、切片进行序列化
   testStruct()
}
//输出
// monster 序列化后 = {"monster_name":"牛魔王","monster_age":500,"Bithday":"2001-11-11","Sal":8000,"Skill":"牛头拳"} 

Json deserialization

json deserializing means, the deserialized into json string corresponding to the type of data (such as the structure, map, slicing) operation

Applications

Show you the json string deserialized into structures, map and sliced

import (
   "encoding/json"
   "fmt"
)
//定义一个结构体
type Monster struct {
   Name string
   Age int
   Birthday string
   Sal float64
   Skill string
}
//演示将json字符串,反序列化成struct
func unmarshalStruct()  {
   //说明str在项目开发中,是通过网络传输获取到.. 或者是读取文件获取到
   str := "{\"Name\":\"牛魔王\",\"Age\":500,\"Birthday\":\"2001-11-11\",\"Sal\":8000,\"Skill\":\"牛头拳\"}"
   //定义一个Monster 实例
   var monster Monster
   err := json.Unmarshal([]byte(str), &monster)
   if err != nil {
      fmt.Printf("unmarshal err = %v\n", err)
   }
   fmt.Printf("反序列化后 monster = %v monster.Name = %v \n", monster, monster.Name)
}
//演示将json字符串,反序列化成map
func unmarshalMap()  {
   str := "{\"address\":\"洪崖洞\",\"age\":30,\"name\":\"红孩儿\"}"
   //定义一个map
   var a map[string]interface{}
   //反序列化
   //注意:反序列化map,不需要make,因为make操作被封装到Unmarshal函数
   err := json.Unmarshal([]byte(str), &a)
   if err != nil {
      fmt.Printf("unmarshal err = %v\n", err)
   }
   fmt.Printf("反序列化后 a = %v\n",a)
}
//演示将json字符串,反序列化成切片1
func unmarshalSlice()  {
   str := "[{\"address\":\"北京\",\"age\":\"7\",\"name\":\"jack\"},"+
      "{\"address\":[\"墨西哥\",\"夏威夷\"],\"age\":\"20\",\"name\":\"tom\"}]"
   //定义一个slice
   var slice []map[string]interface{}
   //反序列化,不需要make,因为make操作被封装到Unmarshal函数
   err := json.Unmarshal([]byte(str), &slice)
   if err != nil {
      fmt.Printf("unmarshal err = %v\n", err)
   }
   fmt.Printf("反序列化后 slice = %v\n", slice)
}

func main()  {
   unmarshalStruct()
   unmarshalMap()
   unmarshalSlice()
}
//输出
//反序列化后 monster = {牛魔王 500 2001-11-11 8000 牛头拳} monster.Name = 牛魔王 
//反序列化后 a = map[address:洪崖洞 age:30 name:红孩儿]
//反序列化后 slice = [map[address:北京 age:7 name:jack] map[address:[墨西哥 夏威夷] age:20 name:tom]]

Precautions

1) When a deserialization json string, to ensure consistency of the data type that the data type and deserialization of the original sequence

2) If json string is acquired by the program, then there is no need to "" escaping

unit test

A look at the demand

At work, encountered such a situation, is to confirm a function, or a module of the results are correct

Such as:

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

traditional method

In the main function, call addUpper function, look at the results of the actual output and expected results are consistent, if consistent, then function properly, otherwise the function has an error, and then modify the error

//一个被测试函数
func addUpper(n int) int {
   res := 0
   for i := 1; i <= n - 1; i++ {
      res += i
   }
   return res
}
func main()  {
   //传统的测试方法,就是在main函数中使用看看结果是否正确
   res := addUpper(10)
   if res != 55 {
      fmt.Printf("addUpper错误 返回值 = %v 期望值 = %v\n ", res, 55)
   } else {
      fmt.Printf("addUpper正确 返回值 = %v 期望值 = %v\n", res, 55)
   }
}
//addUpper错误 返回值 = 45 期望值 = 55

Analysis of the shortcomings of traditional methods

  1. Is not convenient, you need to call in the main function, so you need to modify the main function now if the project is running, it is possible to stop the project

  2. Is not conducive to management, because when we tested more than one function or more modules, you need to write the main function, is not conducive to our management and our clear thinking

  3. Extraction unit testing. -> testing testing framework can solve the problem

unit test

basic introduction

Go language comes with a lightweight test framework for testing and comes with a command to go test implementation unit testing and performance testing, testing frameworks and other similar language testing framework, you can write a test for the corresponding function based on this framework use case, it may be written to a corresponding pressure on the test frame. By unit testing, may address the following issues:

  1. Make sure that each function is running, and operating results are correct

  2. Write code to ensure performance is good

  3. Unit testing timely discovery of programming errors or logic implemented, the problem early exposure to locate the solution to the problem, and performance testing is focused on some of the problems found on the programming, so that the program can also in the case of high concurrency keep it steady

Getting Started

Use Go unit testing, function testing and the sub addUpper

Special Note: When testing, it may be necessary to temporarily exit 360 (because 360 ​​might think the program is to generate test cases Trojans)

Demonstrates how to perform unit tests

run unit tests schematic principle

Quick start unit testing summary

  1. Test case file name must end with _test.go. For example cal_test.go, cal is not fixed

  2. Test function must start with Test, Test + is the general name of the function being tested, such as TestAddUpper

  3. TestAddUpper (t * testing.T) parameter types must be * testing.T

  4. A test case file, there can be multiple test cases Korean, such as TestAddUpper, TestSub

  5. Run the test case instructions

(1) cmd> go test [if run properly, no logs, error logs will be output]

(2) cmd> go test -v [run right or wrong, are output log]

  1. When an error occurs, you can use t.Fatalf to format output an error message and exit the program

  2. t.Logf method may output a corresponding log

  3. Test function, and not on the main function can be performed, this is a test case of convenient place

  4. PASS represents a successful test run, FALL represent test cases fail

  5. Test a single file, the source files must be put under test

​ go test -v cal_test.go cal.go

  1. Testing a single method

​ go test -v -test.run TestAddUpper

Integrated Case

Comprehensive unit test case requirements:

  1. Write a Monster structure, field Name, Age, Skill

  2. Monster binding method to Store, Monster may be a variable (object), the sequence of the saved to a file

  3. Monster binding approach to ReStore, may be a sequence of Monster, read from the file, and deserialize Monster objects, check deserialization name correctly

  4. Programming test case file store_test.go, writing test cases for testing the function TestStore and TestRestore

Code area

monster/monster.go

package monster

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

type Monster struct {
   Name string
   Age int
   Skill string
}
//给Monster绑定方法Store,可以将一个Monster变量(对象),序列化后保存到文件中
func (this *Monster) Store() bool {
   //先序列化
   data, err := json.Marshal(this)
   if err != nil {
      fmt.Println("marshal err =", err)
      return false
   }
   //保存到文件
   filePath := "e:/monster.ser"
   err = ioutil.WriteFile(filePath, data, 0666)
   if err != nil {
      fmt.Println("write file err =",err)
      return false
   }
   return true
}
//给Monster绑定方法ReStore,可以将一个序列化的Monster从文件中读取,
//并反序列化为Monster对象,检查反序列化,名字正确
func (this *Monster) ReStore() bool {
   //1. 先从文件中,读取序列化的字符串
   filePath := "e:/monster.ser"
   data, err := ioutil.ReadFile(filePath)
   if err != nil {
      fmt.Println("ReadFile err =", err)
      return false
   }
   //2. 使用读取到data []byte,对反序列化
   err = json.Unmarshal(data, this)
   if err != nil {
      fmt.Println("UnMarshal err = ", err)
      return false
   }
   return true
}

monster/monster_test.go

package monster

import "testing"
//测试用例,测试Store方法
func TestStore(t *testing.T)  {
   //先创建一个Monster实例
   monster := &Monster{
      Name: "红孩儿",
      Age: 10,
      Skill: "吐火",
   }
   res := monster.Store()
   if !res {
      t.Fatalf("monster.Store() 错误,希望为 = %v 实例为 = %v",true,res)
   }
   t.Logf("monster.Store() 测试成功!")
}
func TestReStore(t *testing.T)  {
   //测试数据是很多,测试很多次,才确定函数,模块..
   //先创建一个Monster实例,不需要制定字段的值
   var monster = &Monster{}
   res := monster.ReStore()
   if !res {
      t.Fatalf("monster.ReStore() 错误,希望为 = %v 实例为 = %v",true,res)
   }
   //进一步判断
   if monster.Name != "红孩儿" {
      t.Fatalf("monster.ReStore() 错误,希望为 = %v 实例为 = %v","红孩儿",monster.Name)
   }
   t.Logf("monster.ReStore() 测试成功!")
}


Guess you like

Origin www.cnblogs.com/zisefeizhu/p/12638713.html