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


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.