Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock AmazonSQS in unit test to not make a call to SQS?

I have the following method in my Java class:

public class AwsHelper {

  private AmazonSQS sqs;

  private void sendMessageToQueue(String message){

        sqs = AmazonSQSClientBuilder.defaultClient();

        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setQueueUrl("");
        sendMessageRequest.setMessageBody(message);
        sendMessageRequest.setMessageGroupId("");

        sqs.sendMessage(sendMessageRequest);
}

I want to be able to mock the behavior of sqs.sendMessage(sendMessageRequest);so that my unit test does not send a message to a queue.

I have tried to do so as follows in my test class, but sqs actually sends a message to the queue when my test is executed. Assume this is due to being assigned by AmazonSQSClientBuilder.defaultClient().

How can I solve this?

public class AwsSQSReferralsUtilTest {
    
        @Spy
        @InjectMocks
        private AwsHelper awsHelper;
    
        @Mock
        AmazonSQS sqs;
    
        @BeforeClass
        public void setUp() {
            MockitoAnnotations.initMocks(this);
        }
    
        @AfterMethod
        public void afterEachMethod() {
            Mockito.reset(awsHelper);
        }
    
        @Test
        public void shouldSendMessage() {
    
            Mockito.when((sqs.sendMessage(any(SendMessageRequest.class)))).thenReturn(new SendMessageResult());
    
            awsHelper.sendMessageToQueue("");
        }
}
like image 367
java12399900 Avatar asked Jan 29 '21 15:01

java12399900


People also ask

What is mock test in Junit?

While doing unit testing using junit you will come across places where you want to mock classes. Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls.

What is Receivecount in SQS?

In SQS, one of the attributes for a message that appears in SQS console in the Receive Count which is a numeric property. After a message is created, the receive count property increases even though no interaction has happened or the same message has not been resent.


Video Answer


2 Answers

I recommend to use approach from article: https://github.com/mockito/mockito/wiki/Mocking-Object-Creation

You need to change little bit a class, applying approach for mocking from article in following way:

AwsHelper

public class AwsHelper {

    private AmazonSQS sqs;

    public void sendMessageToQueue(String message) {
        sqs = defaultClient();

        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setQueueUrl("");
        sendMessageRequest.setMessageBody(message);
        sendMessageRequest.setMessageGroupId("");

        sqs.sendMessage(sendMessageRequest);
    }

    protected AmazonSQS defaultClient() {
        return AmazonSQSClientBuilder.defaultClient();
    }
}

AwsSQSReferralsUtilTest

public class AwsSQSReferralsUtilTest {

    @Spy
    private AwsHelper awsHelper;

    @Mock
    private AmazonSQS sqs;

    @BeforeClass
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }
    
    @AfterMethod
    public void afterEachMethod() {
        Mockito.reset(awsHelper);
    }

    @Test
    public void shouldSendMessage() {
        //mocking object creation
        doReturn(sqs).when(awsHelper).defaultClient();

        when(sqs.sendMessage(any(SendMessageRequest.class))).thenReturn(new SendMessageRequest());
        awsHelper.sendMessageToQueue("");
    }

}
like image 113
saver Avatar answered Oct 10 '22 03:10

saver


Here is an example of using MOCK to test SQS API (sendMessage). It passed and did not send the queue an actual message. When you use MOCK, you are not invoking real AWS endpoints. Its just testing the API - not modifying AWS resources.

enter image description here

Code for SQS Mock

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.io.*;
import java.util.*;
import static org.mockito.Mockito.mock;

@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SQSServiceMock {

    private static SqsClient sqsClient;

    private static String queueName ="";
    private static String queueUrl ="" ; // set dynamically in the test
    private static String message ="";
    private static String dlqueueName ="";
    private static List<Message> messages = null; // set dynamically in the test


    @BeforeAll
    public static void setUp() throws IOException {

        try {
            sqsClient = mock(SqsClient.class);

        } catch (Exception ex) {
            ex.printStackTrace();
        }


        try (InputStream input = SQSServiceIntegrationTest.class.getClassLoader().getResourceAsStream("config.properties")) {

            Properties prop = new Properties();

            if (input == null) {
                System.out.println("Sorry, unable to find config.properties");
                return;
            }

            //load a properties file from class path, inside static method
            prop.load(input);

            // Populate the data members required for all tests
            queueName = prop.getProperty("QueueName");
            message = prop.getProperty("Message");
            dlqueueName=prop.getProperty("DLQueueName");


        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Test
    @Order(1)
    public void whenInitializingAWSS3Service_thenNotNull() {
        assertNotNull(sqsClient);
        System.out.println("Test 1 passed");
    }

    @Test
    @Order(2)
    public void SendMessage() {

        SendMessageRequest sendMsgRequest = SendMessageRequest.builder()
                .queueUrl("https://sqs.us-east-1.amazonaws.com/000000047983/VideoQueue")
                .messageBody(message)
                .delaySeconds(5)
                .build();

        sqsClient.sendMessage(sendMsgRequest);
        System.out.println("Test 2 passed");
    }
}
like image 1
smac2020 Avatar answered Oct 10 '22 02:10

smac2020