英文:
How to mock a function calling io.Copy
问题
尝试模拟以下函数。它基本上从S3中获取一个对象(io.ReadCloser
),并将其写入之前使用os.Open()
打开的文件(io.WriteCloser
)。
package main
import (
"io";
log "github.com/sirupsen/logrus"
)
func writeFile(destination io.WriteCloser, source io.ReadCloser) error {
defer destination.Close()
defer source.Close()
_, err := io.Copy(destination, source)
if err != nil {
log.WithFields(log.Fields{"desc": "无法将内容从S3复制到blahblah"}).Error(err)
return err
}
return nil
}
我认为我离成功很近,但目前我的测试卡住了,既没有出错也没有成功...我还意识到我可以将os.Stdout
传递给目标,但仍然遇到了同样的问题。在io.Copy
中发生了一些问题。我想象中这是因为我试图将空数据复制到空位置?
package main
import (
"errors";
"io";
"reflect";
"testing";
)
type mockReadCloser struct {}
func (m mockReadCloser) Read(p []byte) (int, error) { return 0, nil }
func (m mockReadCloser) Close() error { return nil }
type mockWriteCloser struct{}
func (m mockWriteCloser) Close() error { return nil }
func (m mockWriteCloser) Write(b []byte) (n int, err error) { return 0, nil }
func Test_writeFile(t *testing.T) {
type args struct {
destination io.WriteCloser
source io.ReadCloser
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "",
args: args{
destination: &mockWriteCloser{},
source: &mockReadCloser{},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := writeFile(tt.args.destination, tt.args.source); (err != nil) != tt.wantErr {
t.Errorf("writeFile() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
英文:
Trying to mock the following function. It basically takes an object from S3 (io.ReadCloser
) and writes it to a file that execution os.Open()
d earlier (io.WriteCloser
).
package main
import (
"io"
log "github.com/sirupsen/logrus"
)
func writeFile(destination io.WriteCloser, source io.ReadCloser) error {
defer destination.Close()
defer source.Close()
_, err := io.Copy(destination, source)
if err != nil {
log.WithFields(log.Fields{"desc": "unable to copy contents from s3 to blahblah"}).Error(err)
return err
}
return nil
}
I think I'm pretty close, but at the moment my test hangs and never errors / succeeds... I also realized that I can pass os.Stdout
to my destination, but still ran into the same issue. Something is going on within io.Copy
. I imagine it's because I'm trying to copy empty data to nothing?
package main
import (
"errors"
"io"
"reflect"
"testing"
)
type mockReadCloser struct {}
func (m mockReadCloser) Read(p []byte) (int, error) { return 0, nil }
func (m mockReadCloser) Close() error { return nil }
type mockWriteCloser struct{}
func (m mockWriteCloser) Close() error { return nil }
func (m mockWriteCloser) Write(b []byte) (n int, err error) { return 0, nil }
func Test_writeFile(t *testing.T) {
type args struct {
destination io.WriteCloser
source io.ReadCloser
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "",
args: args{
destination: &mockWriteCloser{},
source: &mockReadCloser{},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := writeFile(tt.args.destination, tt.args.source); (err != nil) != tt.wantErr {
t.Errorf("writeFile() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
答案1
得分: 2
这是因为io.Copy
在遇到EOF或错误之前不会返回。
Copy函数从源(src)复制数据到目标(dst),直到在源上达到EOF或发生错误为止。它返回复制的字节数以及在复制过程中遇到的第一个错误(如果有的话)。
成功的Copy函数返回err == nil,而不是err == EOF。因为Copy函数被定义为从源读取数据直到EOF,它不会将Read返回的EOF视为需要报告的错误。
所以,如果你在mockReadCloser.Read
中返回EOF,它就不会再阻塞了。
func (m mockReadCloser) Read(p []byte) (int, error) { return 0, io.EOF }
这是因为Read函数会重复调用,直到没有更多可读取的内容(EOF)。
for {
nr, er := src.Read(buf)
...
}
英文:
It's because io.Copy doesn't return until EOF or error.
> Copy copies from src to dst until either EOF is reached on src or an error occurs. It returns the number of bytes copied and the first error encountered while copying, if any.
>
> A successful Copy returns err == nil, not err == EOF. Because Copy is defined to read from src until EOF, it does not treat an EOF from Read as an error to be reported.
So, if you return EOF from your mockReadCloser.Read
, it shouldn't hang any more.
func (m mockReadCloser) Read(p []byte) (int, error) { return 0, io.EOF }
This is because Read is called repeatedly until there is nothing more to read (EOF).
for {
nr, er := src.Read(buf)
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论