9
votes

Devrais-je écrire des tests d'unité pour les opérations de CRUD lorsque j'ai déjà des tests d'intégration?

Dans notre récent projet Sonar se plaignait d'une faible couverture de test. Nous avons remarqué que cela n'a pas considéré comme des tests d'intégration par défaut. Outre le fait que vous puissiez configurer Sonar, il y en examinera (Jacoco Plugin), nous discutions de la question de notre équipe s'il est vraiment nécessaire d'écrire des tests d'unité, lorsque vous couvrez tous vos systèmes de service et de base de données avec des tests d'intégration De toute façon.

Qu'est-ce que je veux dire avec les tests d'intégration, c'est que tous nos tests fonctionnent contre une instance d'oracle dédiée du même type que nous utilisons dans la production. Nous ne nous moquons rien. Si un service dépend d'un autre service, nous utilisons le service réel. Données dont nous avons besoin avant d'exécuter un test, nous construisons dans certaines classes d'usine utilisant nos services / référentiels (DAOS).

Donc de mon point de vue - Écrire des tests d'intégration pour des opérations de crud simples, en particulier lorsque l'utilisation de cadres telles que les données de printemps / hibernate n'est pas un gros effort. C'est parfois encore plus facile, car vous ne pensez pas à quoi et à vous moquer de vous moquer.

Alors pourquoi devrais-je écrire des tests d'unité pour mes opérations de crud, moins fiables car les tests d'intégration que je peux écrire?

Le seul point que je vois est que les tests d'intégration prendront plus de temps pour courir, plus le projet obtient. Donc, vous ne voulez pas les courir tout avant l'enregistrement. Mais je ne suis pas si sûr si cela est si grave, si vous avez un environnement CI avec Jenkins / Hudson qui fera le travail.

SO - Toutes les opinions ou suggestions sont très appréciées!


0 commentaires

3 Réponses :


11
votes

Si la plupart de vos services passent simplement à vos DAOS et que vos DAOS ne font que peu, mais invoquent des méthodes sur hibernatetemplate code> ou jdbctemplate code> alors vous êtes correct que l'unité teste que Don 't prouve vraiment tout ce que vos tests d'intégration prouvent déjà. Cependant, les tests d'unités en place sont utiles pour toutes les raisons habituelles.

Étant donné que les tests de l'unité ne testent que des classes simples, exécutées en mémoire sans disque ni accès réseau, et ne testez jamais de multiples classes travaillant ensemble, ils vont normalement comme ça : p>

  • Tests Unité de service se moquent des DAOS. LI>
  • Tests de l'unité DAO Mockez le pilote de base de données (ou le modèle de ressort) ou utilisez une base de données intégrée (super facile au printemps 3). LI> ul>

    Test de l'appareil Test du service qui passe à travers le DAO, vous pouvez vous moquer de la même manière: P>

    private EmbeddedDatabase database;
    private EventDaoJdbcImpl eventDao = new EventDaoJdbcImpl();
    
    @Before
    public void setUp() {
        database = new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .addScript("schema.sql")
                .addScript("init.sql")
                .build();
        eventDao.jdbcTemplate = new JdbcTemplate(database);
    }
    
    @Test
    public void creatingIncrementsSize() {
        Event e = new Event(9, "Company Softball Game");
    
        int initialCount = eventDao.findNumberOfEvents();
        eventDao.createEvent(e);
        assertThat(eventDao.findNumberOfEvents(), is(initialCount + 1));
    }
    
    @Test
    public void deletingDecrementsSize() {
        Event e = new Event(1, "Poker Night");
    
        int initialCount = eventDao.findNumberOfEvents();
        eventDao.deleteEvent(e);
        assertThat(eventDao.findNumberOfEvents(), is(initialCount - 1));
    }
    
    @Test
    public void createdEventCanBeFound() {
        eventDao.createEvent(new Event(9, "Company Softball Game"));
        Event e = eventDao.findEventById(9);
        assertThat(e.getId(), is(9));
        assertThat(e.getName(), is("Company Softball Game"));
    }
    
    @Test
    public void updatesToCreatedEventCanBeRead() {
        eventDao.createEvent(new Event(9, "Company Softball Game"));
        Event e = eventDao.findEventById(9);
        e.setName("Cricket Game");
        eventDao.updateEvent(e);
        e = eventDao.findEventById(9);
        assertThat(e.getId(), is(9));
        assertThat(e.getName(), is("Cricket Game"));
    }
    
    @Test(expected=EventExistsException.class)
    public void creatingDuplicateEventThrowsException() {
        eventDao.createEvent(new Event(1, "Id1WasAlreadyUsed"));
    }
    
    @Test(expected=NoSuchEventException.class)
    public void updatingNonExistentEventThrowsException() {
        eventDao.updateEvent(new Event(1000, "Unknown"));
    }
    
    @Test(expected=NoSuchEventException.class)
    public void deletingNonExistentEventThrowsException() {
        eventDao.deleteEvent(new Event(1000, "Unknown"));
    }
    
    @Test(expected=NoSuchEventException.class)
    public void findingNonExistentEventThrowsException() {
        eventDao.findEventById(1000);
    }
    
    @Test
    public void countOfInitialDataSetIsAsExpected() {
        assertThat(eventDao.findNumberOfEvents(), is(8));
    }
    


2 commentaires

Ray, merci beaucoup quatre explications détaillées et exemples! Je suppose que nous allons coller à l'approche Ecrire des tests d'intégration d'abord. Je vais même aller jusqu'à présent pour dire que des tests d'unités pour les services de crud d'une application Web sont agréables, mais ce qui compte vraiment des tests d'intégration. Et pourquoi ne pas le faire la voie TDD, mais écrire des tests d'intégration au lieu d'essais unitaires avant de mettre en œuvre le service?


Ce sera parfait; La police de test de l'unité ne frappera pas à votre porte. Il est vrai que les tests d'intégration couvrent les tests de l'unité. Personnellement, j'apprécie le sentiment d'avoir les tests de l'unité là-bas (confiance en refactoring, un sentiment de complétude et tout cela) mais c'est juste moi. Si vous êtes heureux de gagner votre couverture grâce à des tests d'intégration par opposition à des tests unitaires, et vos tests d'intégration sont en cours d'exécution rapide des tests d'intégration générée par le développeur, par opposition à l'acceptation du système fonctionnel-System-System-Intet-Intet-Intet-Integration - Tests de production, puis cool. :)



1
votes

Vous n'avez vraiment besoin que de tester chaque couche de manière isolée si vous envisagez de disposer des couches exposées à d'autres composants hors de votre projet. Pour une application Web, la seule manière dont la couche de référentiel peut être appelée, est par la couche Services, et la seule manière dont la couche de service peut être invoquée est par la couche de contrôleur. Les tests peuvent donc démarrer et se terminer à la couche de contrôleur. Pour les tâches de fond, celles-ci sont invoquées dans la couche de service, alors doivent être testées ici.

Test avec une bonne base de données est assez rapide ces jours-ci, alors ne ralentit pas trop vos tests, si vous concevez votre configuration / démolition. Cependant, s'il y a une autre dépendance qui pourrait être lente ou problématique, celles-ci devraient être moquées / stupéfiées.

Cette approche vous donnera:

  • bonne couverture
  • Tests de réalisation
  • quantité minimale d'effort
  • Montant minimum d'effort de réfecteur

    Cependant, les couches de test isolent permettent à votre équipe de travailler plus simultanément, de sorte qu'un device puisse faire un référentiel et un autre peut faire un service pour une fonction de fonctionnalité et produire des travaux testés indépendamment.

    Il y aura toujours une double couverture lorsque les tests sélénium / fonctionnels sont incorporés comme vous ne pouvez pas compter sur eux seuls, car ils sont trop lents à courir. Toutefois, des tests fonctionnels ne doivent pas nécessairement couvrir tout le code, la fonctionnalité principale seule peut être suffisante, aslong que le code a été couvert par des tests d'unité / d'intégration.


0 commentaires

0
votes

Je pense qu'il y a deux avantages d'avoir fini grain (je n'utiliserai pas l'initialement le test de l'unité de mot ici) Tests Outre les tests d'intégration haut de gamme.

1) La redondance, avoir les couches couvertes de plus d'un lieu agit comme un commutateur. Si un ensemble de tests (le test d'intégration F.EX.) ne parvient pas à localiser l'erreur, la deuxième couche peut l'attraper. Je dessinerai une comparaison ici avec des interrupteurs électriques où la redondance est un must. Vous avez un interrupteur principal et un commutateur spécialisé.

2) suppose que vous ayez un processus appelant service externe. Pour une ou une autre raison (bug), l'exception originale reçoit le consommateur et une exception qui ne porte pas d'informations sur la nature technique de l'erreur atteint le test d'intégration. Le test d'intégration attrapera l'erreur, mais vous n'aurez aucune idée de l'erreur ou de l'origine. Avoir un test de grain fin en place augmente les chances de pointer dans la direction correcte. Quoi et où l'excédantage a échoué.

Je pense personnellement que certains niveaux de redondance dans les tests ne sont pas une mauvaise chose.

Dans votre cas particulier Si vous écrivez un test de crud avec la base de données de mémoire, vous aurez la possibilité de tester votre couche de mappage hibernate qui peut être assez complexe si vous utilisez des choses comme en cascade ou la récupération et ainsi de suite ... < / p>


0 commentaires