首页 > 其他分享 >golang 单元测试 命令行 日志打印 测试结果打印控制台

golang 单元测试 命令行 日志打印 测试结果打印控制台

时间:2025-01-11 22:22:09浏览次数:1  
标签:pb log err 打印 单元测试 golang func go

golang 单元测试 命令行 日志打印 测试结果打印控制台

test.bat

@REM go test -timeout 30s -run ^TestMultiPong$ github.com/jergoo/go-grpc-tutorial/ping

@REM go test -timeout 30s -run ^TestPing$ github.com/jergoo/go-grpc-tutorial/ping


@REM go test -timeout 30s -run ^TestPingV1$ github.com/jergoo/go-grpc-tutorial/ping

		
        ▼▼ 添加-v (verbose) 添加到命令行参数中,控制台打印日志信息
go test -v -timeout 30s -run ^TestPingV2$ github.com/jergoo/go-grpc-tutorial/ping

go.mod

module github.com/jergoo/go-grpc-tutorial

go 1.19

require (
	github.com/golang/protobuf v1.5.2
	google.golang.org/grpc v1.51.0
	google.golang.org/protobuf v1.28.1
)

require (
	golang.org/x/net v0.2.0 // indirect
	golang.org/x/sys v0.2.0 // indirect
	golang.org/x/text v0.4.0 // indirect
	google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
)

go.sum

github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c=
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=


ping\client.go


package main

import (
	"context"
	"io"
	"log"
	"time"

	"google.golang.org/grpc"

	pb "github.com/jergoo/go-grpc-tutorial/protos/ping" // 引入编译生成的包
)

// Ping 单次请求-响应模式
func Ping() {
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	// 实例化客户端并调用
	client := pb.NewPingPongClient(conn)

	res, err := client.Ping(context.Background(), &pb.PingRequest{Value: "ping"})

	if err != nil {
		log.Fatal(err)
	}
	log.Println(res.Value)
}

// MultiPong 服务端流模式
func MultiPong() {
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	// 实例化客户端并调用
	client := pb.NewPingPongClient(conn)
	// 获得对 stream 对象的引用
	stream, err := client.MultiPong(context.Background(), &pb.PingRequest{Value: "ping"})
	if err != nil {
		log.Fatal(err)
	}

	// 循环接收数据流
	for {
		msg, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}
		log.Println(msg.Value)
	}
}

// MultiPing 客户端流模式
func MultiPing() {
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	// 实例化客户端并调用
	client := pb.NewPingPongClient(conn)
	stream, err := client.MultiPing(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 发送数据
	for i := 0; i < 5; i++ {
		data := &pb.PingRequest{Value: "ping"}
		err = stream.Send(data)
		if err != nil {
			log.Fatal(err)
		}
	}

	// 发送结束并获取服务端响应
	res, err := stream.CloseAndRecv()
	if err != nil {
		log.Fatal(err)
	}

	log.Println(res.Value)
}

// MultiPingPong 双向流模式
func MultiPingPong() {
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	// 实例化客户端并调用
	client := pb.NewPingPongClient(conn)
	stream, err := client.MultiPingPong(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 在另一个goroutine中接收数据
	c := make(chan struct{})
	go func(stream pb.PingPong_MultiPingPongClient, c chan struct{}) {
		defer func() {
			c <- struct{}{}
		}()
		for {
			msg, err := stream.Recv()
			if err != nil {
				if err == io.EOF {
					break
				}
				log.Fatal(err)
			}
			log.Printf("recv:%s\n", msg.Value)
		}
	}(stream, c)

	// 发送数据
	for i := 0; i < 6; i++ {
		data := &pb.PingRequest{Value: "ping"}
		err = stream.Send(data)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("send:%s\n", data.Value)
		time.Sleep(500 * time.Millisecond)
	}

	// 结束发送
	stream.CloseSend()
	// 等待接收完成
	<-c
}

ping\client_test.go


package main

import (
	"testing"
)

func TestPing(t *testing.T) {
	tests := []struct {
		name string
	}{
		{name: "ping"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			Ping()
		})
	}
}

func TestMultiPong(t *testing.T) {
	tests := []struct {
		name string
	}{
		{name: "multi pong"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			MultiPong()
		})
	}
}

func TestMultiPing(t *testing.T) {
	tests := []struct {
		name string
	}{
		{name: "multi ping"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			MultiPing()
		})
	}
}

func TestMultiPingPong(t *testing.T) {
	tests := []struct {
		name string
	}{
		{name: "multi ping&pong"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			MultiPingPong()
		})
	}
}

ping\clinet_v1_test.go


package main

import (
	"io"
	"log"
	"net"
	"sync"
	"testing"

	pb "github.com/jergoo/go-grpc-tutorial/protos/ping"
	"google.golang.org/grpc"
)

// 定义一个全局变量用于保存服务端实例,方便后续关闭操作
var srv *grpc.Server

// 启动server的函数,和server.go中的启动逻辑类似,但做了简化调整以适应测试环境
func startServer() {
	var err error
	srv = grpc.NewServer()
	pb.RegisterPingPongServer(srv, &PingPongServer{})
	lis, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		if err := srv.Serve(lis); err != nil && err != io.EOF {
			log.Fatal(err)
		}
	}()
}

// 关闭server的函数
func stopServer() {
	srv.GracefulStop()
}

// 定义一个结构体来保存测试相关的上下文信息,比如WaitGroup
type TestContext struct {
	wg sync.WaitGroup
}

// 初始化测试上下文
func NewTestContext() *TestContext {
	return &TestContext{
		wg: sync.WaitGroup{},
	}
}

// 测试结束时的清理函数,用于关闭服务端
func (tc *TestContext) Cleanup() {
	stopServer()
	tc.wg.Wait()
}

func TestPingV1(t *testing.T) {
	ctx := NewTestContext()
	defer ctx.Cleanup()

	// 在测试的时候启动服务端,虽然省事,不是不建议
	startServer()

	tests := []struct {
		name string
	}{
		{name: "ping"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx.wg.Add(1)
			log.Println("ping")
			Ping()
			ctx.wg.Done()
		})
	}
}

ping\clinet_v2_test.go


package main

import (
	"fmt"
	"log"
	"os"
	"testing"
)

// 产生测试文件
func TestPingV2(t *testing.T) {
	// 创建一个日志文件
	logFile, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("无法创建日志文件: %v", err)
	}
	defer logFile.Close()
	// 设置日志输出到文件
	log.SetOutput(logFile)

	tests := []struct {
		name string
	}{
		{name: "ping"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			log.Println("ping")
			fmt.Println("Ping result:") // 打印Ping函数的返回结果
			Ping()
		})
	}
}

ping\server.go


package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net"

	"google.golang.org/grpc"

	pb "github.com/jergoo/go-grpc-tutorial/protos/ping" // 引入编译生成的包
)

// PingPongServer 实现 pb.PingPongServer 接口
type PingPongServer struct {
	pb.UnimplementedPingPongServer // 兼容性需要,避免未实现server接口全部方法
}

// Ping 单次请求-响应模式
func (s *PingPongServer) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PongResponse, error) {
	println("server: receive ping")
	return &pb.PongResponse{Value: "pong"}, nil
}

// MultiPong 服务端流模式
func (s *PingPongServer) MultiPong(req *pb.PingRequest, stream pb.PingPong_MultiPongServer) error {
	for i := 0; i < 10; i++ {
		data := &pb.PongResponse{Value: "pong"}
		// 发送消息
		err := stream.Send(data)
		if err != nil {
			return err
		}
	}
	return nil
}

// MultiPing 客户端流模式
func (s *PingPongServer) MultiPing(stream pb.PingPong_MultiPingServer) error {
	msgs := []string{}
	for {
		// 提前结束接收消息
		if len(msgs) > 5 {
			return stream.SendAndClose(&pb.PongResponse{Value: "ping enough, max 5"})
		}

		msg, err := stream.Recv()
		if err != nil {
			// 客户端消息结束,返回响应信息
			if err == io.EOF {
				return stream.SendAndClose(&pb.PongResponse{Value: fmt.Sprintf("got %d ping", len(msgs))})
			}
			return err
		}
		msgs = append(msgs, msg.Value)
	}
}

// MultiPingPong 双向流模式
func (s *PingPongServer) MultiPingPong(stream pb.PingPong_MultiPingPongServer) error {
	msgs := []string{}
	for {
		// 接收消息
		msg, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		msgs = append(msgs, msg.Value)

		// 每收到两个消息响应一次
		if len(msgs)%2 == 0 {
			err = stream.Send(&pb.PongResponse{Value: "pong"})
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// 启动server
func main() {
	srv := grpc.NewServer()
	// 注册 PingPongServer
	pb.RegisterPingPongServer(srv, &PingPongServer{})
	lis, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal(err)
	}
	log.Println("listen on 1234")
	srv.Serve(lis)
}

标签:pb,log,err,打印,单元测试,golang,func,go
From: https://www.cnblogs.com/zhuoss/p/18666278

相关文章

  • 软件测试全景解析:单元测试、系统测试与集成测试
    引言在现代软件开发中,测试是确保软件质量和稳定性的关键环节。通过不同层次的测试,能够有效地发现并解决程序中的错误,提升产品的可靠性和用户体验。常见的测试类型包括单元测试、集成测试和系统测试,它们分别针对软件开发的不同阶段和层次,发挥着不可或缺的作用。本文将详细阐述......
  • Golang——rune和byte
    本文详细介绍Golang中的两种字符类型rune和byte,介绍他们的区别,编码方式和简单的使用。文章目录`byte`类型`rune`类型UTF-8与Unicode的关系byte和rune的主要区别Go的默认编码方式遍历方式遍历`byte`遍历`rune`补充字符还原从`byte`序列还原字符串从`rune`......
  • Golang——Go语言基础知识
    本文详细介绍Go语言的基础知识,包括数据类型,深浅拷贝,编程范式,Go语言是一种静态(静态类型语言和静态语言)强类型、编译型、并发型,并具有垃圾回收功能的编程语言。文章目录1.Go语言基础知识数据类型基本数据类型基本数据类型复合数据类型深拷贝与浅拷贝浅拷贝(Shallo......
  • 32单片机从入门到精通之测试与验证——单元测试(十五)
    人生苦短,我们都会面临困难和挑战。但是,只要我们保持积极的心态和勇往直前的精神,我们就能战胜一切困难,实现自己的目标。成功并不是一蹴而就的,它需要我们付出努力和坚持不懈。就像爬山一样,我们可能会遇到陡峭的山路和艰难的攀登,但只要我们不放弃,不停止前进,就一定能登上山顶,看到......
  • Word 转成pdf及打印的开源方案支持xp
    Word转成pdf、打印的方案几乎没有免费开源的方案,现在提供一个通过LibreOffice实现的方案操作依赖LibreOffice需要安装,点此下载老版本5.4.7.2是最后一个支持xp的版本如需xp要请安装此版本LibreOffice官方介绍LibreOffice是一款开放源代码的自由免费全能办公软件,可运行于M......
  • Golang笔记——切片与数组
    本文详细介绍Golang的切片与数组,包括他们的联系,区别,底层实现和使用注意事项等。文章目录数组与切片的异同相同之处区别切片(Slice)源码解析Go源码中`len()`和`cap()`定义长度与容量示例`append()`函数Go切片扩容机制基本原理扩容策略(依据Go版本)扩容源码解......
  • Golang笔记——hashmap
    本文详细介绍golang的哈希表的底层实现、扩容机制、插入查询过程以及并发安全性。文章目录定义Key无序性Key唯一性Key可比性基本使用底层实现哈希表实现hmapbucket数据结构bmap链地址法哈希冲突负载因子扩容增量扩容等量扩容查找过程插入过程删除流程非并发安全......
  • RICOH---理光打印机使用
    记录一下公司打印机,RICOH的使用方法:一、常见的使用方法1、扫描使用方法:通常在局域网里面设置后,可以在网络里面查看到打印机: 双击进入:选择【设备管理】点【配置】       二、常见问题1、扫描提示:发送者名称未被注册至通讯薄 处理:点击【用户工具计数器】......
  • C#对Excel打印时,PageSetup 对象详解
    C#对Excel打印时,PageSetup对象详解 PageSetup对象包含所有页面设置的属性(左边距、底部边距、纸张大小等)。下面按“页面”、“页边距”、“页眉/页脚”、“工作表”和“无对应选项卡”五个类别,逐一介绍。一、页面与“页面”选项卡对应的属性有7个。分别为:PrintQuality、Orien......
  • Java后端开发单元测试
    测试概览测试是用于促进鉴定软件正确性、完整性、安全性和软件质量的过程。在开发的过程中测试是必不可少的,测试一般分为四个阶段:单元测试,集成测试,系统测试,验收测试;对于后端开发人员而言,需要会单元测试和集成测试。测试的方法一般分为三种:白盒测试,黑盒测试,灰盒测试:白盒测试......