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

I'm trying to write tests for this function in 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 }
}

I'd like to have a fake /etc/passwd so that my tests can create the necessary users in that file instead of relying on the real system file.

For other parts of my code, I abstracted the underlying file system using Afero to create an in-memory file system, creating the necessary files (including /etc/passwd) so the tests can run. That's what the fs field in LinuxBackend is for.

For example, here's another function from the same package:

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

I can then test this without touching the real file system:

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) + "
")
    f.WriteString("UID_MAX           " + strconv.Itoa(uidMax) + "
")
}

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...
}

I can't do that for user.Lookup(), though, which means it will try to fetch the non-existent test users from the real file system.

user.Lookup calls user.lookupUser, which has two concrete implementations, a pure Go one, and a cgo one. The latter is completely impossible to coerce to use a virtual file system, I believe, since it uses libc's pw* utility functions to fetch users. The former starts by Opening a file handle and then passes it to a findUsername function that takes an io.Reader as an argument, but this function is not exported from the module, so I can't use it directly to pass a Reader from the Afero file system to it.

Is there a way I can somehow make Go use the in-memory file system for user.Lookup and user.lookupUser, or write the code or test in some other way so that user.Lookup doesn't use the real file system?

I could always copy user.lookupUser but I'd rather avoid that.