J'ai la tâche de créer des implémentations pour un grand nombre de structures de données métriques (nommément Quadtree et arborescence KD variantes). J'ai environ quatre de ces implémentations, mais la façon dont je suis testant actuellement n'est pas, pour mon manque de meilleur mot, bon.
J'ai besoin d'un moyen propre pour tester l'insertion et la suppression des données de ces arbres / Trie structures d'une manière que je puisse tester les structures internes des nœuds (vérifiant les parents, les enfants, la commande, etc.). Ces implémentations suivent les preuves distinctes et les analyses d'exécution de l'exactitude, je dois donc vous assurer que non seulement un nœud est inséré correctement (signification, récupérable de l'arbre plus tard), mais aussi dans une position très "correcte" dans l'arbre. P>
"Test de l'unité" semble être le mauvais moyen d'y aller à ce sujet, cependant, comme ça se passe, si je ne me trompe pas, est de tester une API externe de la structure ou du système. J'ai vu beaucoup de questions relatives aux tests d'unité posant "Comment puis-je avoir accès à un champ privé dans un test de l'unité" ou "Comment tester les valeurs de retour d'une méthode non publique" et la réponse est généralement "pas" T "- et je suis d'accord avec cette réponse. P>
Et donc je ne laissez personne disposé à vous aider avec des ramblings vagues, l'interface que mes arbres implémentent sont les suivantes (basée sur l'interface de carte de Java Collection): P>
public interface SpatialMap<K, V> extends Iterable<SpatialMap.Entry<K, V>>
{
// Query Operations
/**
* Returns the number of key-value mappings in this map. If the map contains more than
* <tt>Integer.MAX_VALUE</tt> elements, returns <tt>Integer.MAX_VALUE</tt>.
*
* @return The number of key-value mappings in this map.
*/
int size();
/**
* Returns <tt>true</tt> if this map contains no key-value mappings.
*
* @return <tt>true</tt> if this map contains no key-value mappings.
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this map contains a mapping for the specified key.
*
* @param key
* The key whose presence in this map is to be tested.
* @return <tt>true</tt> if this map contains a mapping for the specified key.
*/
boolean containsKey(K key);
/**
* Returns the value to which the specified key is mapped, or {@code null} if this map contains
* no mapping for the key.
*
* <p>A return value of {@code null} does not <i>necessarily</i> indicate that the map contains
* no mapping for the key; it's also possible that the map explicitly maps the key to
* {@code null}. The {@link #containsKey containsKey} operation may be used to distinguish these
* two cases.
*
* @see #put(Comparable, Comparable, Object)
*
* @param key
* The key whose associated value is to be returned.
* @return The value to which the specified key is mapped, or {@code null} if this map contains
* no mapping for the key.
*/
V get(K key);
// Modification Operations
/**
* Associates the specified value with the specified key in this map. If the map previously
* contained a mapping for the key, the old value is replaced.
*
* @param key
* The key with which the specified value is to be associated.
* @param data
* The value to be associated with the specified key.
* @return The previous value associated with the key, or <tt>null</tt> if there was no mapping
* for the key. (A <tt>null</tt> return can also indicate that the map previously
* associated <tt>null</tt> with <tt>key</tt>.)
*/
V put(K key, V data);
/**
* Removes the mapping for the specified key from this map if present.
*
* @param key
* The key whose mapping is to be removed from the map.
* @return The previous value associated with the key, or <tt>null</tt> if there was no mapping
* for the key. (A <tt>null</tt> return can also indicate that the map previously
* associated <tt>null</tt> with <tt>key</tt>.)
*/
V remove(K key);
// Bulk Operations
/**
* Removes all of the mappings from this map. The map will be empty after this call returns.
*/
void clear();
}
3 Réponses :
Il y a des cas comme celui-ci où parfois vous avez vraiment besoin de tester l'état interne d'une structure. Dans ce cas, j'accéderais aux variables internes à l'aide de la réflexion. Il y a quelques addons junit (privateAccessor http://junit-addons.sourceforge.net/ junitx / util / privateACECCESSOR.html ) qui facilite la tâche. P>
Le compromis est que votre test sera plus fragile, car si l'état interne change, votre test peut casser. Mais si vous voulez que votre état interne soit correct, vous devez parfois faire cela. P>
L'état interne en ce qui concerne les commandes de noeuds devraient ne jamais changer, tant que mes preuves de correction sont réellement correctes;)
À droite, mais si les noms variables changent par exemple, le test peut casser. Ceci est plus d'un test d'unité Whitebox (par opposition à Blackbox). Parfois, ce style est approprié et on dirait dans votre cas, c'est ce que vous recherchez.
Une méthode que j'ai utilisée dans ce type de situation est de faire protéger ces champs internes et de créer une sous-classe pour les tests. À travers cette sous-classe, vous pouvez exposer n'importe quel état nécessaire à vos tests de boîte blanche. P>
Si vous mettez l'interface et sa (s) interface (s) seule dans un package dédié et effectuez les méthodes d'état internes de cette implémentation Ce n'est pas bon pour les tests unitaires "Purist", mais c'est généralement comment je vais à ce sujet, quand je ne veux pas exposer les courages de ma classe dans le reste du système, mais je veux toujours faire des affirmations sur son comportement interne. p>