gpt4 book ai didi

unit-testing - 单元测试中模拟/伪造/替换硬件相关功能

转载 作者:行者123 更新时间:2023-12-03 02:24:57 28 4
gpt4 key购买 nike

我目前在一个文件中有以下函数:

func pinExported(pin int) bool {
pinPath := fmt.Sprintf("/sys/class/gpio/gpio%d", pin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}

同一文件中的另一个代码部分使用上述函数,如下所示:

func isGpioPinExported(gpioPin int) bool {
exported := pinExported(gpioPin)
for !exported && (timeOut < timeOutForPinExportInMilliseconds) {
timeOut++
time.Sleep(1 * time.Millisecond)
exported = pinExported(gpioPin)
}
...

所以现在我正在寻找一种优雅的方法来模拟/替换单元测试中的上述 pinExported 函数,以测试 isGpioPinExported 内部的逻辑,因为函数 pinExported 取决于硬件(Raspberry PI)。

一种解决方案可能是使 pinExported 函数成为 isGpioPinExported 的参数

因此定义一个这样的函数类型:

type pinExported func(int) int

这意味着我必须像这样定义isGpioPinExported:

isGpioPinExported(pinExported pinExported, gpioPin int) bool {
exported := pinExported(gpioPin)
for !exported && (timeOut < timeOutForPinExportInMilliseconds) {
...
}
..
}

现在我可以毫无问题地编写单元测试并定义模拟/假pinExported。到目前为止,一切都很好。但我有大约五六个这样的函数,这意味着它会导致将五六个补充参数放入像 isGpioPinExported 这样的函数中,这是完全错误的。除此之外,问题是如果没有在测试中运行,我在哪里可以定义使用的默认实现?

最佳答案

因此,根据 mkopriva 的建议,我创建了一个如下所示的界面(现在具有三个函数来查看其实际工作原理):

type Raspberry interface {
isPinExported(gpioPin int) bool
valueExist(gpioPin int) bool
directionExist(gpioPin int) bool
}

进一步定义了一个结构体来实现真实硬件(Raspberry):

type Rasberry3Plus struct {
}

func (raspberry Rasberry3Plus) valueExist(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d/value", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}

func (raspberry Rasberry3Plus) directionExist(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d/direction", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}

func (raspberry Rasberry3Plus) isPinExported(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}

使用上述函数的函数IsGpioPinExported现在看起来像这样(这只是一个示例实现,用于了解模拟测试如何工作):

func IsGpioPinExported(raspberry Raspberry, gpioPin int) bool {
pinExported := raspberry.isPinExported(gpioPin)
valueExist := raspberry.valueExist(gpioPin)
directionExist := raspberry.directionExist(gpioPin)

return valueExist && directionExist && pinExported
}

现在测试看起来像这样。首先,我必须定义一个类型(顺便说一句:我决定使用 Mock):

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

type mockRaspberry struct {
mock.Mock
}

func (raspMock mockRaspberry) isPinExported(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func (raspMock mockRaspberry) valueExist(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func (raspMock mockRaspberry) directionExist(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}

func Test_ValueTrue_DirectionExistTrue(t *testing.T) {
testObj := new(mockRaspberry)

testObj.On("isPinExported", 5).Return(false)
testObj.On("valueExist", 5).Return(true)
testObj.On("directionExist", 5).Return(true)

exported := IsGpioPinExported(testObj, 5)
assert.Equal(t, false, exported)
}

现在可以很简单地使用适当的模拟函数来测试函数 IsGpioPinExported 中的逻辑并获得所需的结果。最后主程序如下所示:

func main() {
rasberry3Plus := gpio.Rasberry3Plus{}
gpio.IsGpioPinExported(rasberry3Plus, 23)
}

关于unit-testing - 单元测试中模拟/伪造/替换硬件相关功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57841971/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com