It is a very simple unit test case.
I have two methods in class School
:
protected S3Object getAwsObject(AmazonS3Client client, String bucketName, String keyName) {
GetObjectRequest objRequest = new GetObjectRequest(bucketName, keyName);
return client.getObject(objRequest);
}
Above method is invoked by the 2nd method showing below:
public void doTask() {
// get client
AmazonS3Client client = getAwsS3Client();
// invoke the 1st method
S3Object s3Obj = getAwsObject(client, "my-bucket", "my-key");
...
}
I use Mockito to test the method doTask()
, I tried to mock the AmazonS3Client
& stub function getAwsObject()
:
@Test
public void testDoTask() {
// partially mocked School instance
School school = new School();
School schoolSpy = Mockito.spy(school);
// mock the client & s3 object
AmazonS3Client mockedClient = Mockito.mock(AmazonS3Client.class);
S3Object mockedS3Obj = Mockito.mock(S3Object.class);
Mockito.doReturn(mockedClient)
.when(schoolSpy).getAwsS3Client();
// PROBLEM HERE: I stub function to return mocked S3Object, but real code is run
Mockito.doReturn(mockedS3Obj)
.when(schoolSpy).getAwsObject(mockedClient, "my-bucket", "my-key");
// system under test
schoolSpy.doTask();
}
When run the test, I got the following error:
com.amazonaws.services.s3.model.AmazonS3Exception:
The AWS Access Key Id you provided does not exist in our records.
(Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 6B973FC095C28524),...
Looks like the test case run the real code client.getObject(objRequest)
instead of using the stub of getAwsObject(...)
, WHY?
If you don't succeed in making your mocking work, you can solve your problem by overriding the original methods this way:
// mock the client & s3 object
final AmazonS3Client mockedClient = Mockito.mock(AmazonS3Client.class);
final S3Object mockedS3Obj = Mockito.mock(S3Object.class);
School school = new School(){
@Override
protected S3Object getAwsObject(AmazonS3Client client, String bucketName, String keyName) {
return mockedS3Obj;
}
@Override
protected AmazonS3Client getAwsS3Client() {
return mockedClient;
}
};
// system under test
school.doTask();
First, you should not use spy but in legacy code. ( http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html#spy%28T%29 ). If you delegate the creation of objects in not static factories/builders it will be easy to test.
But, in this case, if mockito executes the real code, then your doReturn... is not valid. I think that Mockito does not validate the params clause and then it not launchs the doReturn clause.
You have
doReturn...getAwsObject(mockedClient, "my-bucket", "my-key")
If you do the next and it works then i am right 100%
doReturn...getAwsObject(any(AmazonS3Client.class), anyString(), anyString())
I had problems when i used mock params and not-mock params in the same statement. try this:
getAwsObject(mockedClient, eq("my-bucket"), eq("my-key"));
If this does not work try with another solution like:
eq(mockedClient), eq(...), eq(...)
Finally, if it does not work, maybe @max solution will be easier.
Multiple wrong things are done here.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.