Mocking Amazon SQS For Unit Tests in Go

If you are interacting with SQS from Go you have probably found this article from AWS:

Mocking Out the AWS SDK for Go for Unit Testing

I had a few issues with the article. I didn’t find their implementation very understandable and also I didn’t find their test setup straight forward or flexible. Why create a new syntax/API when we can just use the SQS API? Here it is:

type mockSQS struct {
sqsiface.SQSAPI
messages map[string][]*sqs.Message
}
func (m *mockSQS) SendMessage(in *sqs.SendMessageInput) (*sqs.SendMessageOutput, error) {
m.messages[*in.QueueUrl] = append(m.messages[*in.QueueUrl], &sqs.Message{
Body: in.MessageBody,
})
return &sqs.SendMessageOutput{}, nil
}
func (m *mockSQS) ReceiveMessage(in *sqs.ReceiveMessageInput) (*sqs.ReceiveMessageOutput, error) {
if len(m.messages[*in.QueueUrl]) == 0 {
return &sqs.ReceiveMessageOutput{}, nil
}
response := m.messages[*in.QueueUrl][0:1]
m.messages[*in.QueueUrl] = m.messages[*in.QueueUrl][1:]
return &sqs.ReceiveMessageOutput{
Messages: response,
}, nil
}

Some important points:

  1. This only handles the most basic SendMessage and ReceiveMessage, which is all I needed. You may need to implement more of the many functions in sqsiface.SQSAPI.
  2. It doesn’t handle errors. Since it’s specifically designed to be setup and used in a unit test I didn’t build in the cases that are not possible for my scenarios.
  3. It only handles the raw message body. If your application needs the message attributes, IDs, MD5 hash, etc, you’ll need to add that as well.

Here is an example of usage:

// Not used. This is just here for reference.
func getRealSQSClient() sqsiface.SQSAPI {
sess := session.Must(session.NewSession())
return sqs.New(sess)
}
func getMockSQSClient() sqsiface.SQSAPI {
return &mockSQS{
messages: map[string][]*sqs.Message{},
}
}
func TestQueue(t *testing.T) {
q := getMockSQSClient()
queueURL := "https://queue.amazonaws.com/80398EXAMPLE/MyQueue"
q.SendMessage(&sqs.SendMessageInput{
MessageBody: aws.String("Hello, World!"),
QueueUrl: &queueURL,
})
message, _ := q.ReceiveMessage(&sqs.ReceiveMessageInput{
QueueUrl: &queueURL,
})
assert.Equal(t, *message.Messages[0].Body, "Hello, World!")
}

Since this solution is so rudimentary it’s OK for fast unit tests and to get up and running but it wouldn’t be wise to rely on this as your final testing infrastructure. We use lyft/fake_sqs on our CI for a more robust solution.

Originally published at http://elliot.land on August 9, 2018.

Written by

I’m a data nerd and TDD enthusiast originally from Sydney. Currently working for Uber in New York. My thoughts here are my own. 🤓 elliotchance@gmail.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store