首页 > 解决方案 > 使 os.Stat 抛出错误,使得 IsNotExist 返回 false

问题描述

我正在尝试测试以下分支:

if _, err := os.Stat(path); err != nil {
        if os.IsNotExist(err) {
            continue
        }
        return errors.File().AddDetails(err)
    }

显然,如果不存在os.Stat就会抛出错误。阅读 Golang 文档不会返回有关可能返回的错误的详细信息。有没有办法抛出另一种错误?pathos.Statos.Stat

标签: unit-testinggo

解决方案


我认为您会发现很难通过os.Stat单元测试以独立于平台的方式控制抛出哪些错误以及何时抛出。如果您确实需要对返回未知错误类型的路径进行测试,那么您最好的选择可能是重构您的包代码,以便您可以模拟os.Stat. 虽然你不能os.Stat直接改变 的行为,但是通过利用 Go 具有一流函数的事实,你可以使用一些间接来模拟它,而对代码的更改非常少。如果您的包代码如下所示:

package mypackage

import "os"

...

    if _, err := os.Stat(path); err != nil {
        if os.IsNotExist(err) {
           continue
        }
        return errors.File().AddDetails(err)
    }

...

尝试重构它以使用分配的非导出包范围函数变量os.Stat

package mypackage

import "os"

var osStat = os.Stat

...

    if _, err := osStat(path); err != nil {
        if os.IsNotExist(err) {
           continue
        }
        return errors.File().AddDetails(err)
    }

...

现在,在您的测试代码中(应该与被测代码在同一个包中),您可以重新分配osStat给具有相同签名的任何函数以模拟它:

package mypackage

import (
        "os"
        "testing"
)

func TestNotExistError(t *testing.T) {
    osStat = func(string) (os.FileInfo, error) {
        return nil, os.ErrNotExist
    }
    // in case other test functions depend on the unmocked behavior
    defer func() {
        osStat = os.Stat
    }()

    // rest of the test which triggers the codepath above
}

func TestOtherError(t *testing.T) {
    osStat = func(string) (os.FileInfo, error) {
        return nil, os.ErrInvalid
    }
    // in case other test functions depend on the unmocked behavior
    defer func() {
        osStat = os.Stat
    }()

    // rest of the test which triggers the codepath above
}

...

推荐阅读