如何在Golang中为case函数创建单元测试?

如何在Golang中为case函数创建单元测试? 我正在尝试为switch函数创建一个测试单元,其中我的switch根据Byte值调用不同包中的函数。有人能在这方面帮助我吗?

3 回复

我会相信 switch 语句能如描述般工作。也许你可以测试调用你的函数后产生的某些实际结果或效果?

更多关于如何在Golang中为case函数创建单元测试?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这完全取决于你想测试什么。如果你想确保覆盖所有可能的值,就必须创建一个测试,为 switch case 提供所有值。

你最终可以将值的集合缩减到关键的那些。

单元测试的目的是确保你的代码在修改后仍然有效。

在Golang中为包含switch语句的函数编写单元测试,可以通过模拟(mocking)依赖函数来实现。以下是一个示例:

假设你有以下代码结构:

// handler.go
package handler

import "external/pkg"

func ProcessInput(b byte) error {
    switch b {
    case 0x01:
        return pkg.FunctionA()
    case 0x02:
        return pkg.FunctionB()
    default:
        return pkg.DefaultFunction()
    }
}

对应的单元测试可以这样编写:

// handler_test.go
package handler

import (
    "testing"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

// 创建mock结构体
type MockPkg struct {
    mock.Mock
}

func (m *MockPkg) FunctionA() error {
    args := m.Called()
    return args.Error(0)
}

func (m *MockPkg) FunctionB() error {
    args := m.Called()
    return args.Error(0)
}

func (m *MockPkg) DefaultFunction() error {
    args := m.Called()
    return args.Error(0)
}

func TestProcessInput(t *testing.T) {
    tests := []struct {
        name        string
        input       byte
        setupMock   func(*MockPkg)
        expectedErr bool
    }{
        {
            name:  "case 0x01 calls FunctionA",
            input: 0x01,
            setupMock: func(m *MockPkg) {
                m.On("FunctionA").Return(nil)
            },
            expectedErr: false,
        },
        {
            name:  "case 0x02 calls FunctionB",
            input: 0x02,
            setupMock: func(m *MockPkg) {
                m.On("FunctionB").Return(nil)
            },
            expectedErr: false,
        },
        {
            name:  "default case calls DefaultFunction",
            input: 0x03,
            setupMock: func(m *MockPkg) {
                m.On("DefaultFunction").Return(nil)
            },
            expectedErr: false,
        },
        {
            name:  "FunctionA returns error",
            input: 0x01,
            setupMock: func(m *MockPkg) {
                m.On("FunctionA").Return(assert.AnError)
            },
            expectedErr: true,
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            mockPkg := &MockPkg{}
            tt.setupMock(mockPkg)
            
            // 在实际代码中需要通过依赖注入替换pkg包
            // 这里为了演示,假设我们已经通过接口进行了重构
            
            // 执行测试
            err := ProcessInputWithDependency(tt.input, mockPkg)
            
            if tt.expectedErr {
                assert.Error(t, err)
            } else {
                assert.NoError(t, err)
            }
            
            mockPkg.AssertExpectations(t)
        })
    }
}

如果需要保持原有代码结构不变,可以使用接口进行重构:

// handler.go
package handler

type Processor interface {
    FunctionA() error
    FunctionB() error
    DefaultFunction() error
}

func ProcessInputWithDependency(b byte, p Processor) error {
    switch b {
    case 0x01:
        return p.FunctionA()
    case 0x02:
        return p.FunctionB()
    default:
        return p.DefaultFunction()
    }
}

对于简单的测试,也可以使用表格驱动测试而不需要mock:

func TestProcessInput_Simple(t *testing.T) {
    tests := []struct {
        name  string
        input byte
        want  string // 期望调用的函数名
    }{
        {name: "case 0x01", input: 0x01, want: "FunctionA"},
        {name: "case 0x02", input: 0x02, want: "FunctionB"},
        {name: "default case", input: 0x03, want: "DefaultFunction"},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // 这里可以通过其他方式验证函数调用
            // 例如使用全局变量记录调用信息
            calledFunction = ""
            _ = ProcessInput(tt.input)
            if calledFunction != tt.want {
                t.Errorf("ProcessInput() called %s, want %s", calledFunction, tt.want)
            }
        })
    }
}

运行测试:

go test -v ./...
回到顶部