18 votes

Quels tests unitaires écrire pour une classe utilisant des generics en Java ?

En prenant l'exemple très précis de la classe JpaDao définie dans cet article:

public abstract class JpaDao implements Dao {
    protected Class entityClass;

    @PersistenceContext
    protected EntityManager entityManager;

    public JpaDao() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class) genericSuperclass.getActualTypeArguments()[1];
    }

    public void persist(E entity) { entityManager.persist(entity); }

    public void remove(E entity) { entityManager.remove(entity); }

    public E findById(K id) { return entityManager.find(entityClass, id); }
}

serait-il préférable d'écrire des tests unitaires pour toutes les entités existantes dans l'application (Order, Customer, Livre, etc.), ou serait-il acceptable d'écrire des tests unitaires pour une seule entité, comme suggéré par cette autre question? Y a-t-il des bonnes pratiques concernant les tests unitaires des classes Java utilisant des génériques?

8voto

Marty Pitt Points 8239

Vous pourriez écrire une classe de test abstraite pour les entités qui héritent de celle-ci.

Par exemple:

public abstract class JpaDaoTest {

    abstract protected E getEntity();
    abstract protected JpaDao getDAO();

    @Test
    public void testPersistCreatesEntity()
    {
        JpaDao dao = getDAO();
        dao.persist(getEntity());
        // assert
    }
}

Le contrat implémenté par vos classes génériques devrait pouvoir être testé de manière tout aussi générique, en supposant que getEntity() configure correctement les dépendances relationnelles.

Ainsi, en héritant de cette classe de test pour tous les cas de test de vos sous-classes génériques, vous obtenez les tests gratuitement.

2voto

rancidfishbreath Points 2509

De la FAQ JUnit:

4) Dans quelles conditions devrais-je tester les méthodes get() et set()?

Les tests unitaires visent à éliminer la peur que quelque chose puisse se casser. Si vous pensez qu'une méthode get() ou set() pourrait raisonnablement causer une panne, ou a en fait contribué à un défaut, alors écrivez un test.

En bref, testez jusqu'à ce que vous soyez confiant. Ce que vous choisissez de tester est subjectif, basé sur vos expériences et votre niveau de confiance. N'oubliez pas d'être pratique et de maximiser votre investissement dans les tests.

Il est également dit:

"Testez jusqu'à ce que la peur se transforme en ennui."

Je ne pense pas que votre question soit spécifique aux génériques puisque la question resterait la même même si vous n'utilisiez pas de génériques. Dans ce cas, je choisirais de tester un objet (réel ou préparé à des fins de test). En cas de problèmes découverts, rédigez ensuite des tests pour corriger ces déficiences spécifiques.

1voto

Bill the Lizard Points 147311

Si l'utilisation d'un type d'entité différent provoque l'exécution de code différent, alors vous avez besoin d'un cas de test séparé.

Je testerais autant que possible dans un ensemble de tests communs n'utilisant qu'un seul type d'entité. Si la plupart de votre code traite toutes les entités de la même manière, alors il n'est pas nécessaire de le tester plus d'une fois. Je mettrais en place des cas de test séparés pour tout comportement spécial requis où les DAO d'entités spécifiques ont un comportement différent.

1voto

Davidann Points 3405

Tout comme BalusC, je recommande de tester les implémentations concrètes. La raison en est qu'elle est conforme au principe "Vous n'en aurez pas besoin". Ajoutez juste assez de tests pour que le cas d'utilisation que vous essayez d'implémenter réussisse. Ensuite, à mesure que vous ajoutez plus de cas d'utilisation, ajoutez plus de tests unitaires.

0voto

Sergey Mikhanov Points 1730

Si je devais tester le comportement de la classe en ce qui concerne ses sémantiques de type, je vérifierais les invariants de type. En d'autres termes, essayez d'établir certaines assertions qui sont vraies pour toutes les combinaisons de types, pas seulement celles que vous prévoyez d'utiliser mais n'importe quel type dans l'univers, y compris ceux qui ne sont pas encore inventés. Par exemple :

private  void testTypes(K k, E e) {
    JpaDao dao = new JpaDaoImpl();

    dao.persist(e);

    assertEquals(dao.getById(e.getId()).getClass(), e.getClass());
}

@Test
public void testIntegerAndOrder() {
    this.testTypes(10, new Order());
}

Vous voyez, peu importe les types K et E, les assertions doivent être vraies (la méthode testIntegerAndOrder() teste cette assertion en utilisant des valeurs de type concrets).

Cela devrait bien sûr être utilisé en conjonction avec les tests unitaires, qui testent réellement le comportement pour des valeurs de type variables particulières. Ce sera très similaire aux tests unitaires que vous pourriez trouver dans n'importe quel tutoriel JUnit. Quelque chose dans le genre :

@Test
public void testDao() throws Exception {
    JpaDao dao = getDao();

    Order order = ...;
    order.setId(10);

    dao.persist(order);

    assertEquals(order, dao.findById(10));
}

Vous voyez comment les sémantiques des assertions diffèrent ici : ce test vérifie une assertion selon laquelle l'objet stocké détient son ID en utilisant une valeur concrète de la variable ID, et non la variable de type comme le test précédent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X