我是编写单元测试的新手。我正在尝试读取存储在S3
中的JSON文件,并且收到“传递给when()的参数不是模拟对象!”的信息。和“配置文件不能为空”错误。
这是我到目前为止尝试过的 Retrieving Object Using JAVA:
private void amazonS3Read() {
String clientRegion = "us-east-1";
String bucketName = "version";
String key = "version.txt";
S3Object fullObject = null;
try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.withCredentials(new ProfileCredentialsProvider())
.build();
fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key));
S3ObjectInputStream s3is = fullObject.getObjectContent();
json = returnStringFromInputStream(s3is);
fullObject.close();
s3is.close();
} catch (AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
} catch (SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//Do some operations with the data
}
测试文件
@Test
public void amazonS3ReadTest() throws Exception {
String bucket = "version";
String keyName = "version.json";
InputStream inputStream = null;
S3Object s3Object = Mockito.mock(S3Object.class);
GetObjectRequest getObjectRequest = Mockito.mock(GetObjectRequest.class);
getObjectRequest = new GetObjectRequest(bucket, keyName);
AmazonS3 client = Mockito.mock(AmazonS3.class);
Mockito.doNothing().when(AmazonS3ClientBuilder.standard());
client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.withCredentials(new ProfileCredentialsProvider())
.build();
Mockito.doReturn(s3Object).when(client).getObject(getObjectRequest);
s3Object = client.getObject(getObjectRequest);
Mockito.doReturn(inputStream).when(s3Object).getObjectContent();
inputStream = s3Object.getObjectContent();
//performing other operations
}
获得两个不同的例外:
Argument passed to when() is not a mock! Example of correct stubbing: doThrow(new RuntimeException()).when(mock).someMethod();
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
OR
profile file cannot be null
java.lang.IllegalArgumentException: profile file cannot be null
at com.amazonaws.util.ValidationUtils.assertNotNull(ValidationUtils.java:37)
at com.amazonaws.auth.profile.ProfilesConfigFile.<init>(ProfilesConfigFile.java:142)
at com.amazonaws.auth.profile.ProfilesConfigFile.<init>(ProfilesConfigFile.java:133)
at com.amazonaws.auth.profile.ProfilesConfigFile.<init>(ProfilesConfigFile.java:100)
at com.amazonaws.auth.profile.ProfileCredentialsProvider.getCredentials(ProfileCredentialsProvider.java:135)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.getCredentialsFromContext(AmazonHttpClient.java:1184)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.runBeforeRequestHandlers(AmazonHttpClient.java:774)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:726)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:719)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:701)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:669)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:651)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:515)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4443)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4390)
at com.amazonaws.services.s3.AmazonS3Client.getObject(AmazonS3Client.java:1427)
我在做什么错,我该如何解决?
答案 0 :(得分:1)
您的方法看起来不对。
amazonS3Read()
,并且您似乎想对该方法进行单元测试。public/protected
方法对类进行测试。 assertEquals(...)
惯用语声明的结果。我会建议您两件事:
编写一个单元测试,该单元测试的重点是断言您执行的逻辑:计算/转换/传输的值,因此……对于链接方法,请不要关注。
使用一些轻便且简单的S3兼容服务器编写一些集成测试,这些测试将为您提供有关行为断言的真实反馈。副作用可以通过这种方式进行测试。
例如,您有Riak,MinIo或仍然是Localstack。
更具体地讲,这是一种重构方法,可以改善功能。
如果必须amazonS3Read()
私有方法进行单一测试,则可能应将其移至特定的类中,例如MyAwsClient
,并将其设为公共方法。
然后这个想法是要使amazonS3Read()
在责任方面尽可能明确。
其逻辑可以总结为:
1)获取一些标识符信息以传递到S3服务。
这意味着使用以下参数定义方法:
public Result amazonS3Read(String clientRegion, String bucketName, String key) {...}
2)应用所有细粒度的S3函数以获得S3ObjectInputStream
对象。
我们可以在类AmazonS3Facade
的特定方法中收集所有这些信息:
S3ObjectInputStream s3is = amazonS3Facade.getObjectContent(clientRegion, bucketName, key);
3)执行正在处理返回的S3ObjectInputStream
并返回结果的逻辑
json = returnStringFromInputStream(s3is);
// ...
return result;
现在如何测试?
足够简单了。
使用JUnit 5:
@ExtendWith(MockitoExtension.class)
public MyAwsClientTest{
MyAwsClient myAwsClient;
@Mock
AmazonS3Facade amazonS3FacadeMock;
@Before
void before(){
myAwsClient = new MyAwsClient(amazonS3FacadeMock);
}
@Test
void amazonS3Read(){
// given
String clientRegion = "us-east-1";
String bucketName = "version";
String key = "version.txt";
S3ObjectInputStream s3IsFromMock = ... // provide a stream with a real content. We rely on it to perform the assertion
Mockito.when(amazonS3FacadeMock.getObjectContent(clientRegion, bucketName, key))
.thenReturn(s3IsFromMock);
// when
Result result = myAwsClient.amazonS3Read(clientRegion, bucketName, key);
// assert result content.
Assertions.assertEquals(...);
}
}
有什么优势?
AmazonS3Facade
(单一职责原理/模块化)。 请注意,单一测试AmazonS3Facade
几乎没有价值,因为这只是对S3组件的一系列调用,无法根据返回结果进行断言,因此非常脆弱。
但是,如前所述,使用一个简单且轻便的S3兼容服务器为它编写一个集成测试确实有意义。
答案 1 :(得分:0)
您的错误提示:
传递给when()的参数不是模拟的!
您正在aria-label="Your preferred text here"
中传递AmazonS3ClientBuilder.standard()
,这不是一个模拟,这就是为什么它不起作用的原因。
考虑使用PowerMock来模拟静态方法。
Here是一个例子。