我如何测试调用用户的Golang代码。如何使用虚拟文件系统(如Afero的内存FS)进行查找?

时间:2018-11-04 17:27:29

标签: unit-testing go testing

我正在尝试在Go中为此功能编写测试:

type LinuxBackend struct {
    fs afero.Fs
}


func (b *LinuxBackend) GetSSHUser(name string) users.SSHUser {
    // Get the user from the system
    usr, err := user.Lookup(name)
    if err != nil {
        panic(err)
    }

    return users.SSHUser{ User: usr }
}

我想要一个假的/etc/passwd,以便我的测试可以在该文件中创建必要的用户,而不是依赖于真实的系统文件。

对于代码的其他部分,我使用Afero抽象了基础文件系统,以创建内存中文件系统,并创建必要的文件(包括/etc/passwd),以便可以运行测试。这就是fsLinuxBackend字段的作用。

例如,这是同一包中的另一个函数:

func (b *LinuxBackend) GetMinMaxUid() (int, int) {
    content, err := afero.ReadFile(b.fs, LoginDefsPath)
    // more code here...
    return min, max
}

然后我可以在不接触真实文件系统的情况下进行测试:

func createLoginDefs(afs afero.Fs) {
    afs.MkdirAll("/etc", os.FileMode(os.ModeDir))
    f, _ := afs.OpenFile(LoginDefsPath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
    defer f.Close()
    f.WriteString("UID_MIN           " + strconv.Itoa(uidMin) + "\n")
    f.WriteString("UID_MAX           " + strconv.Itoa(uidMax) + "\n")
}

func TestLinuxBackend_GetMinMaxUid(t *testing.T) {
    afs := afero.NewMemMapFs() // <-- This is the trick.
    createLoginDefs(afs)

    backend := LinuxBackend{afs}

    min, max := backend.GetMinMaxUid()

    // rest of the test...
}

不过,对于user.Lookup(),我无法做到这一点,这意味着它将尝试从真实文件系统中获取不存在的测试用户。

user.Lookup调用user.lookupUser,它具有两个具体的实现,一个pure Go和一个cgo one。我认为,后者完全不可能强迫使用虚拟文件系统,因为后者使用libc的pw*实用程序功能来获取用户。前者通过Open设置文件句柄开始,然后将其传递到以findUsername作为参数的io.Reader函数,但是该函数未从模块中导出,因此我可以不能直接使用它来将Reader从Afero文件系统传递给它。

有没有一种方法可以使Go使用user.Lookupuser.lookupUser的内存文件系统,或者以其他方式编写代码或测试,以便user.Lookup可以不使用真实的文件系统?

我总是可以复制user.lookupUser,但我宁愿避免这样做。

0 个答案:

没有答案