Résumé: Je ne sais pas comment gérer un seul "Map.Entry" lorsqu'il est renvoyé par un appel de méthode. Dans mon cas particulier, je dois me moquer de cela (en utilisant actuellement mockito) mais ma question porte autant sur la manière de traiter "Map.Entry" que sur la moquerie ... apprécié.
============================
J'ai une méthode comme la suivante. Je dois créer une entité correspondante (une Map.Entry que je suppose) pour que la maquette revienne lorsque la méthode est appelée. Je ne sais pas comment créer une seule Map.Entry. J'ai retracé les appels jusqu'à l'appel SQL vers la base de données, mais je ne peux trouver qu'un point où l'objet retourné est converti en Map.Entry.
Aucune indication sur la façon de construire une telle chose. J'ai besoin d'aide pour construire un seul "Map.Entry" qui peut être retourné par le simulacre.
assertTrue(The Key == SomeDate) assertTrue(The Value == True)
Voici une ligne qui créerait l'objet simulé pour moi. Pour simplifier, supposons que la méthode ci-dessus soit dans la classe "Foo".
when(foo.getLastModifiedGid(any())).thenReturn(the Map.Entry I don't know how to make yet);
Ensuite, j'aurais besoin de quelque chose comme ça pour dire que lorsque la méthode est appelée (comme un simulacre ), il doit renvoyer le "Map.Entry" que j'ai besoin de construire.
Foo foo = mock(Foo.class);
Enfin, j'ai besoin d'affirmer quelque chose de testable à propos de Map.Entry qui est retourné. Je suis prêt à vérifier la clé et la valeur dans l'assert - rien de plus sophistiqué que cela n'est requis - encore une fois, je ne suis pas sûr de savoir comment j'accéderais à cela en tant que Map.Entry ...
public Map.Entry<Date,Boolean> getLastModified(SomeClass someClass) throws Exception { return clusterViewDataProvider.getClusterModified(someClass); }
Si je n'ai pas été clair sur quoi que ce soit, veuillez commenter et je clarifierai. Gratzi.
3 Réponses :
Vous pouvez implémenter votre propre entrée
when(foo.getLastModifiedGid(any())).thenReturn(new DummyEntry(...))
Et la renvoyer ensuite dans votre maquette.
class DummyEntry<K,V> implements Map.Entry<K, V> { K key; V value; public DummyEntry(K key, V value) { this.key = key; this.value = value; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V value) { this.value = value; return value; } }
La création de votre propre classe Entry personnalisée nécessite beaucoup d'implémentation de code supplémentaire uniquement pour le cas des tests .
Cela devrait être un drapeau rouge pour la conception de tests, car il est probable que vous compliquiez le problème beaucoup plus qu'il ne le devrait.
Au lieu de cela, pourquoi ne pas créer une carte réelle et avoir la carte fait le travail?
//define your expected response element Date foo = ...; Boolean bar = ...; //instantiate map Map<Date,Boolean> dummyMap = new HashMap<>(); dummyMap.put(foo, bar); //fetch an actual working copy from a functional map Map.Entry<Date, Boolean> baz = dummyMap.entrySet().stream().findFirst().get(); //mock away when(foo.getLastModifiedGid(any())).thenReturn(baz);
Je ne sais pas pourquoi vous affirmeriez quelque chose concernant l'entrée elle-même. Si vous le définissez, ce devrait être le vôtre. Si votre méthode en cours de test la modifie, testez les résultats, et non l'objet prédéfini que vous lui avez fourni.
Je suis d'accord sur la question du test de l'entrée - dans ce cas, je me moque d'un "hit" sur une base de données - je ne veux pas frapper la base de données dans un test unitaire, comme je suis sûr que vous serez d'accord. . Ce "hit" à la base de données est de plusieurs niveaux de profondeur et je suppose que ce que je fais est de "tester" que rien entre les deux ne mute ce que cet appel de niveau profond retourne ... meilleure utilisation de mon temps, mais les règles d'entreprise imposent une couverture de code élevée - et donc je les écris ...
Il n'est pas nécessaire de créer votre propre implémentation de Map.Entry
. Vous pouvez utiliser l'une des implémentations existantes comme AbstractMap.SimpleEntry
:
Map.Entry<Date, Boolean> entry = new AbstractMap.SimpleImmutableEntry<>(date, value);
ou AbstractMap.SimpleImmutableEntry
: p >
Date date = new Date(); boolean value = true; Map.Entry<Date, Boolean> entry = new AbstractMap.SimpleEntry<>(date, value); when(foo.getLastModifiedGid(any())).thenReturn(entry);
En remarque, les classes de date de java.util
sont obesolètes et les classes de java.time
doivent être utilisées pour Java 8+. Plus précisément, java.util.Date
est remplacé par java.time.Instant
.
Bon point sur java.time . Et même pour Java 6 et Java 7, il est préférable d'utiliser la bibliothèque back-port, ThreeTen- Backport , que d'utiliser les terribles classes de date-heure héritées telles que Date
.
D'accord - Je me moque du code hérité pour les tests unitaires qui auraient dû être écrits il y a longtemps - donc l'utilisation de Date ...
Accédez au javadoc de Map.Entry: docs .oracle.com / javase / 8 / docs / api / java / util / Map.Entry.html . Regardez la liste des classes d'implémentation. Choisissez celui que vous préférez. Créez une instance de cette classe.
Comment placer une Map.Entry dans un HashMap? Comment accepter la valeur de retour de cette méthode? Peu importe l'instance de la classe d'implémentation que j'utilise probablement, mais je ne sais pas à quoi ressemblerait le code et la lecture de la documentation n'est pas très utile dans ce cas. Un échantillon de code serait apprécié. Ce lien suggère que ce n'est pas simple ... stackoverflow.com/questions/39441096/...
when (foo.getLastModifiedGid (any ())). thenReturn (new AbstractMap.SimpleEntry (someKey, someValue))
@JBNizet Merci beaucoup!
J'ai également trouvé cette approche pour créer mon "objet à renvoyer par un faux" Map.Entry me = new AbstractMap.SimpleImmutableEntry <> (new Date (), Boolean.TRUE);