2
votes

Comment puis-je tester l'unité la méthode getObject du SDK AWS S3 à l'aide de Java?

Je travaille avec Java et j'utilise le kit AWS SDK pour interagir avec S3. J'ai la méthode suivante et je veux la tester unitaire

ResponseInputStream<GetObjectResponse> 

Pour cela, j'utilise JUnit 5 et Mockito. Le problème est que je ne sais pas comment me moquer du résultat de

s3Client.getObject(getObjectRequest) 

car le type de retour

private final S3Client s3Client;
...
...
public byte[] download(String key) throws IOException {
    GetObjectRequest getObjectRequest = GetObjectRequest.builder()
            .bucket("myBucket")
            .key(key)
            .build();
    return s3Client.getObject(getObjectRequest).readAllBytes();
}

est une classe finale.

Une idée ou des suggestions? Merci


3 commentaires

Si vous ne pouvez pas simplement créer un objet ResponseInputStream correspondant, vous souhaiterez probablement activer la simulation finale comme décrit dans le docu . Êtes-vous sûr de la classe, je ne peux pas voir une méthode readAllBytes() sur cette classe (au moins dans la latest version )?


s3Client.getObject (getObjectRequest) renvoie un ResponseInputStream <GetObjectResponse> qui étend indirectement java.io.InputStream


Apparemment, la méthode a été ajoutée dans java 9 tandis que la documentation que j'ai liée se réfère à une version java plus ancienne qui n'avait pas cette méthode.


4 Réponses :


0
votes

J'ai pu mettre cela en marche dans Spock avec un GroovyMock qui utilise Objenesis. Je sais que ce n'est pas la pile de l'affiche originale, mais cela est venu dans ma recherche, alors j'ai pensé que je répondrais ici au cas où des parties de cette affiche aideraient quelqu'un d'autre.

S3Repo à tester

import software.amazon.awssdk.core.ResponseInputStream
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.GetObjectRequest
import spock.lang.Specification

class S3RepoTest extends Specification {

    def "get object text"() {
        given:
        def response = GroovyMock(ResponseInputStream)
        def s3Text = 'this would be in file stored in s3'
        def key = 'my-file.txt'
        def s3 = Mock(S3Client)
        def bucket = 'mock-bucket'
        def repo = new S3Repo(s3: s3, bucket: bucket)

        when:
        def text = repo.getS3ObjectText(key)

        then:
        1 * s3.getObject(_) >> { args ->
            def req = args.first() as GetObjectRequest
            assert req.bucket() == bucket
            assert req.key() == key
            return response
        }
        1 * response.text >> s3Text

        and:
        text == s3Text
    }
}

Test de Spock

import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.GetObjectRequest

class S3Repo {
    S3Client s3
    String bucket

    def getS3ObjectText(String key) {
        def response
        try {
            response = s3.getObject(GetObjectRequest
                    .builder().bucket(bucket).key(key).build() as GetObjectRequest)
            return response.text
        } finally {
            if (response) response.close()
        }
    }
}

Je pense que l'élément critique ici est le GroovyMock qui nécessite Objenesis. Vous pouvez certainement tester votre code Java avec Groovy et vous pourriez probablement utiliser GroovyMock dans JUnit.


0 commentaires

1
votes

Le problème est résolu. Dans un projet maven, vous pouvez ajouter un fichier nommé "org.mockito.plugins.MockMaker" dans le dossier "src / test / resources / mockito-extensions".

Dans le fichier, ajoutez "mock-maker-inline" sans guillemets.

Désormais, Mockito pourra également se moquer des classes finales.


0 commentaires

0
votes

Je l'ai fait dans un projet gradle. Ajoutez les dépendances suivantes -

    testCompile group: 'net.bytebuddy', name: 'byte-buddy-agent', version: '1.9.10'
    testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.7.21'
    compile group: 'net.bytebuddy', name: 'byte-buddy', version: '1.9.10'

Les dépendances bytebuddy sont des dépendances de compilation requises pour que mockito-core supporte les dépendances mockito-inline. (Réf - https://howtodoinjava.com/mockito/plugin-mockmaker-error/ https://mvnrepository.com/artifact/org.mockito/mockito-core/2.27.2 (voir les dépendances de compilation ici))

A pu se moquer de la méthode getObject après cela.


0 commentaires

0
votes

Au cas où quelqu'un cherche encore une solution différente, voici comment je l'ai fait:
C'est le code qu'il faut se moquer:

S3Client s3Client = Mockito.mock(S3Client.class);
String bucket = "bucket";
String key = "key";
InputStream objectStream = getFakeInputStream();
when(s3Client.getObject(
        Mockito.any(GetObjectRequest.class),
        ArgumentMatchers
            .<ResponseTransformer<GetObjectResponse, ResponseInputStream<GetObjectResponse>>>
                any()))
    .then(
        invocation -> {
          GetObjectRequest getObjectRequest = invocation.getArgument(0);
          assertEquals(bucket, getObjectRequest.bucket());
          assertEquals(key, getObjectRequest.key());

          return new ResponseInputStream<>(
              GetObjectResponse.builder().build(), AbortableInputStream.create(objectStream));
        });

Voici comment se moquer:

InputStream objectStream =
    this.s3Client.getObject(
        GetObjectRequest.builder().bucket(bucket).key(key).build(),
        ResponseTransformer.toInputStream());


0 commentaires