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
4 Réponses :
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.
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 } }
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.
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.
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.
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());
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éthodereadAllBytes()
sur cette classe (au moins dans lalatest 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.