Reputation: 19
Here is some code
type Combiner interface {
Combine(files []io.Reader) (io.Reader, error)
}
type CsvCombiner struct {
hasHeader bool
}
func (c *csvCombiner) Combine(files []io.Reader) (io.Reader, error) {
combinedCSV := &bytes.Buffer{}
writer := csv.NewWriter(combinedCSV)
reader := csv.NewReader(file[0])
header, err := reader.Read()
if err != nil {
return nil, err
}
if err := writer.Write(header); err != nil {
return nil, err
}
// more code...
}
How would I write a test case for when writer.Write() fails? I'm finding it difficult to mock calls on structs that do not implement an interface (csv.Writer).
I've tried creating a separate interface:
type CSVWriter interface {
Write(record []string) error
Flush()
Error() error
}
and mocking it with testify/mock
type MockCSVWriter struct {
mock.Mock
}
func (m *MockCSVWriter) Write(record []string) error {
args := m.Called(record)
return args.Error(0)
}
func (m *MockCSVWriter) Flush() {
m.Called()
return
}
func (m *MockCSVWriter) Error() error {
args := m.Called()
return args.Error(0)
}
but this chunk of code doesn't mock the writer.Write() call
var mockCSVWriter MockCSVWriter
defer mockCSVWriter.AssertExpectations(t)
mockCSVWriter.On("Write", mock.Anything).Return(expectedError).Once()
Any suggestions would be greatly appreciated!
Upvotes: 0
Views: 410
Reputation: 303
MockCSVWriter is not being sent to the CsvCombiner and new one is getting created always at writer := csv.NewWriter(combinedCSV)
.
Have a field in CsvCombiner to hold the CSVWriter, which can be replaced with the mocked one. type to be of interface that csv.Writer and MockCSVWriter both satisfy
Better approach will be to Mock interface io.Writer
that is supplied to csv.NewWriter
instead and pass this as a field in CsvCombiner
struct.
type CsvCombiner struct {
hasHeader bool
writer io.Writer // This will be "injected" with mock
}
func (c *CsvCombiner) Combine() (io.Reader, error) {
writer := csv.NewWriter(c.writer) // Use struct field io.writer
header := []string{"sada", "sasa"}
if err := writer.Write(header); err != nil {
return nil, err
}
// more code...
}
Mock interface and usage
// A mock of io.Writer
type MockIOWriter struct {
mock.Mock
}
func (mw *MockIOWriter) Write(p []byte) (n int, err error) {
args := mw.Called(p)
return 1, args.Error(0)
}
// Mock usage
mockIOWriter := &MockIOWriter{}
mockIOWriter.On("Write", mock.Anything).Return(expectedError).Once()
wrt := &CsvCombiner{writer: mockIOWriter}
wrt.Combine()
Also, write error can be thrown during csv Writer methods Write() and/or Flush() so check with writer.Error()
for getting the error
Upvotes: 0