如何在单元测试中模拟 AmazonSQS 以不调用 SQS?
How to mock AmazonSQS in unit test to not make a call to SQS?
我的 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);
}
我希望能够模拟 sqs.sendMessage(sendMessageRequest);
的行为,以便我的单元测试不会向队列发送消息。
我在我的测试 class 中尝试这样做,但是 sqs
实际上在我的测试执行时向队列发送了一条消息。假设这是由 AmazonSQSClientBuilder.defaultClient()
.
分配的
我该如何解决这个问题?
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("");
}
}
这里有一个使用MOCK测试SQS的例子API(sendMessage)。它通过了并且没有向队列发送实际消息。当您使用 MOCK 时,您并不是在调用真正的 AWS 端点。它只是测试 API - 不修改 AWS 资源。
SQS 模拟代码
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");
}
}
我推荐使用文章中的方法:https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
您需要稍微改变一下 class,按照以下方式应用文章中的模拟方法:
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("");
}
}
Mocking static methods with Mockito 是可能的,使用 PowerMock
.
以下测试有效:
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.amazonaws.services.sqs.model.SendMessageResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.ArgumentMatchers.any;
@RunWith(PowerMockRunner.class)
@PrepareForTest(AmazonSQSClientBuilder.class)
public class AwsSQSReferralsUtilTest {
private AwsHelper awsHelper = new AwsHelper();
@Mock
AmazonSQS sqs;
@BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@AfterMethod
public void afterEachMethod() {
Mockito.reset(awsHelper);
}
@Test
public void shouldSendMessage() {
PowerMockito.mockStatic(AmazonSQSClientBuilder.class);
BDDMockito.given(AmazonSQSClientBuilder.defaultClient()).willReturn(sqs);
Mockito.when((sqs.sendMessage(any(SendMessageRequest.class)))).thenReturn(new SendMessageResult());
awsHelper.sendMessageToQueue("");
}
}
无需更改任何源代码。我不确定您是否可以使用它,因为此解决方案使用 junit
,而您使用 testng
.
标记了问题
在尝试 运行 与 testng
时,我遇到了这个问题:
powermock not prepared for test
所以我使用 post .
解决了它
我的 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);
}
我希望能够模拟 sqs.sendMessage(sendMessageRequest);
的行为,以便我的单元测试不会向队列发送消息。
我在我的测试 class 中尝试这样做,但是 sqs
实际上在我的测试执行时向队列发送了一条消息。假设这是由 AmazonSQSClientBuilder.defaultClient()
.
我该如何解决这个问题?
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("");
}
}
这里有一个使用MOCK测试SQS的例子API(sendMessage)。它通过了并且没有向队列发送实际消息。当您使用 MOCK 时,您并不是在调用真正的 AWS 端点。它只是测试 API - 不修改 AWS 资源。
SQS 模拟代码
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");
}
}
我推荐使用文章中的方法:https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
您需要稍微改变一下 class,按照以下方式应用文章中的模拟方法:
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("");
}
}
Mocking static methods with Mockito 是可能的,使用 PowerMock
.
以下测试有效:
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.amazonaws.services.sqs.model.SendMessageResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.ArgumentMatchers.any;
@RunWith(PowerMockRunner.class)
@PrepareForTest(AmazonSQSClientBuilder.class)
public class AwsSQSReferralsUtilTest {
private AwsHelper awsHelper = new AwsHelper();
@Mock
AmazonSQS sqs;
@BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@AfterMethod
public void afterEachMethod() {
Mockito.reset(awsHelper);
}
@Test
public void shouldSendMessage() {
PowerMockito.mockStatic(AmazonSQSClientBuilder.class);
BDDMockito.given(AmazonSQSClientBuilder.defaultClient()).willReturn(sqs);
Mockito.when((sqs.sendMessage(any(SendMessageRequest.class)))).thenReturn(new SendMessageResult());
awsHelper.sendMessageToQueue("");
}
}
无需更改任何源代码。我不确定您是否可以使用它,因为此解决方案使用 junit
,而您使用 testng
.
在尝试 运行 与 testng
时,我遇到了这个问题:
powermock not prepared for test
所以我使用 post