testify icon indicating copy to clipboard operation
testify copied to clipboard

.On().Return() doesn't enforce expectation for the returned value

Open andrehoong-pixieset opened this issue 11 months ago • 1 comments

Hey guys I have this test:

func TestDownloadFromS3Error1(t *testing.T) {
	mockS3Interface := &MockS3Interface{
		Error: errors.New("something went wrong on download"),
	}
	mockS3Interface.On("GetObject", &s3.GetObjectInput{
		Bucket: aws.String(testBucket),
		Key:    aws.String(testKey),
	}).Return(nil, "aaaaa").Once()

	client := awsclient.AWSClient{
		S3Interface: mockS3Interface,
	}

	downloadFile, _ := os.CreateTemp(os.TempDir(), "testDownloadFromS3-*.txt")
	defer downloadFile.Close()
	defer os.Remove(downloadFile.Name())

	client.DownloadFromS3(testBucket, testKey, downloadFile)

	mockS3Interface.AssertExpectations(t)
	downloadFileInfo, _ := downloadFile.Stat()
 	if downloadFileInfo.Size() != 0 {
		t.Fatalf("The downloaded file should be empty on S3 failure")
	}

	expectedLog := fmt.Sprintf("Error downloading from S3:\n%s", mockS3Interface.Error.Error())
	assertLogsContain(expectedLog, t)
}

Which is implementing this mocked function:

// GetObject is a mock implementation of the GetObject method
func (m *MockS3Interface) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
	m.Called(input)

	if m.Error != nil {
		return nil, m.Error
	}

	return &s3.GetObjectOutput{
		Body: io.NopCloser(bytes.NewReader([]byte(m.Body))),
	}, nil
}

I notice that the expected return value is not actually being enforced. IE: my MockS3Interface is given the error "something went wrong on download", but the expected error to be returned is "aaaaa" (defined after the .On call). Even though the expected return "aaaa" differs from what is actually returned the test still passes

I know I can do something like args := m.Called(input) to get the values defined in .Return() but shouldn't the expected return values also be enforced similar to how the arguments passed into On()are.

I'm still a noob when it comes to Golang and mocking so this might just be a misunderstanding on my end, but any insight is greatly appreciated. Thanks in advance!

andrehoong-pixieset avatar Mar 09 '24 01:03 andrehoong-pixieset

Your mock is wrong, it should look like this:

func (m *MockS3Interface) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
	args := m.Called(input)
	return args.Get(0).(*s3.GetObjectOutput), args.Error(1)
}

And MockS3Interface should have no fields.

brackendawson avatar Mar 10 '24 23:03 brackendawson