Comment tester les méthodes DAO en utilisant Mockito?

j'ai commencé à découvrir la bibliothèque Mockito et il y a une question pour laquelle je n'ai pas trouvé la bonne réponse.

si j'ai par exemple une telle méthode dans ma classe UserDAO qui sauve l'utilisateur dans la base de données:

public class UserDAO{
...
 public void create(User user) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet generatedKeys = null;
        try {

            connection = getConnection();
            pstmt = connection.prepareStatement(INSERT_USER,
                    PreparedStatement.RETURN_GENERATED_KEYS);
            int counter = 1;
            pstmt.setString(counter++, user.getFirstName());
            pstmt.setString(counter++, user.getLastName());
            pstmt.setString(counter++, user.getEmail());
            pstmt.setString(counter++, user.getPassword());
            pstmt.setString(counter++, user.getRole());
            pstmt.setString(counter, user.getLang());

            pstmt.execute();
            connection.commit();
            generatedKeys = pstmt.getGeneratedKeys();

            if (generatedKeys.next()) {
                user.setId(generatedKeys.getInt(Fields.GENERATED_KEY));
            }
        } catch (SQLException e) {
            rollback(connection);
            LOG.error("Can not create a user", e);
        } finally {
            close(connection);
            close(pstmt);
            close(generatedKeys);
        }
    }
  ....
}

comment le tester ?

si je veux tester par exemple une classe DAO, alors je dois créer un DataSource faux, Connection faux, ResultSet faux, etc ? Et donc ne pas tester la base de données elle-même ?

Mais si je veux aussi tester l' comportement du dao et de la base de données ?

pourriez-vous s'il vous plaît produire quelques exemples de code, des liens qui pourraient être utiles et montrer les meilleures approches de le faire ?

23
demandé sur marknorkin 2015-02-08 01:28:28

4 réponses

voici un bon début en utilisant Mockito pour tester votre UserDAO. Ce code utilise une bonne partie des fonctionnalités de Mockito, de sorte que vous pouvez voir comment les utiliser. Laissez-moi savoir si vous avez des questions.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import org.mockito.Mock;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class TestUserDAO {

    @Mock
    DataSource mockDataSource;
    @Mock
    Connection mockConn;
    @Mock
    PreparedStatement mockPreparedStmnt;
    @Mock
    ResultSet mockResultSet;
    int userId = 100;

    public TestUserDAO() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() {
    }

    @Before
    public void setUp() throws SQLException {
        when(mockDataSource.getConnection()).thenReturn(mockConn);
        when(mockDataSource.getConnection(anyString(), anyString())).thenReturn(mockConn);
        doNothing().when(mockConn).commit();
        when(mockConn.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStmnt);
        doNothing().when(mockPreparedStmnt).setString(anyInt(), anyString());
        when(mockPreparedStmnt.execute()).thenReturn(Boolean.TRUE);
        when(mockPreparedStmnt.getGeneratedKeys()).thenReturn(mockResultSet);
        when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE);
        when(mockResultSet.getInt(Fields.GENERATED_KEYS)).thenReturn(userId);
    }

    @After
    public void tearDown() {
    }

    @Test
    public void testCreateWithNoExceptions() throws SQLException {

        UserDAO instance = new UserDAO(mockDataSource);
        instance.create(new User());

        //verify and assert
        verify(mockConn, times(1)).prepareStatement(anyString(), anyInt());
        verify(mockPreparedStmnt, times(6)).setString(anyInt(), anyString());
        verify(mockPreparedStmnt, times(1)).execute();
        verify(mockConn, times(1)).commit();
        verify(mockResultSet, times(2)).next();
        verify(mockResultSet, times(1)).getInt(Fields.GENERATED_KEYS);
    }

    @Test(expected = SQLException.class)
    public void testCreateWithPreparedStmntException() throws SQLException {

         //mock
         when(mockConn.prepareStatement(anyString(), anyInt())).thenThrow(new SQLException());


        try {
            UserDAO instance = new UserDAO(mockDataSource);
            instance.create(new User());
        } catch (SQLException se) {
            //verify and assert
            verify(mockConn, times(1)).prepareStatement(anyString(), anyInt());
            verify(mockPreparedStmnt, times(0)).setString(anyInt(), anyString());
            verify(mockPreparedStmnt, times(0)).execute();
            verify(mockConn, times(0)).commit();
            verify(mockResultSet, times(0)).next();
            verify(mockResultSet, times(0)).getInt(Fields.GENERATED_KEYS);
            throw se;
        }

    }
}
19
répondu Jose Martinez 2015-02-08 13:03:22

mais que faire si je veux aussi tester le comportement de dao et de la base de données ?

Si vous voulez tester la base de données (que vous devriez!), il n'y a aucun moyen de le contourner - Vous avez besoin d'une base de données réelle. Mockito, mais étant une grande bibliothèque, est probablement le mauvais outil pour ce travail.

5
répondu Mureinik 2015-02-07 22:36:43

Un outil comme DBUnit combiné avec JUnit pourrait vous aider à tester vos Oad avec la base de données. DBUnit vous aide à insérer des données de test dans la base de données avant votre UnitTest et comparer les données dans la base de données avec votre attente après le test.

1
répondu pommes 2015-02-07 22:47:31

Ici est de savoir comment vous devrait test:

public class UserDAOTest extends IntegrationTests
{
    // Or do it in a @Before method, if needed.
    UserDAO dao = new UserDAO();

    @Test
    public void createValidUser() {
        User validUser = new User(
            "John", "Smith", "johns@gmail.com", "Abc123!@",
            "admin", "en"); // or use setters as needed

        dao.create(validUser);

        assertEntityCreatedInDB(validUser);
    }

    @Test
    public void attemptToCreateInvalidUser() {
        User invalidUser = new User("", null, null, "", null, "XY");

        dao.create(invalidUser);

        // This really shouldn't be done this way, as DAOs are not supposed
        // to manage transactions; instead, a suitable, descriptive
        // exception should be thrown by the DAO and checked in the test.
        assertTransactionWasRolledBack();
    }
}

quelques remarques à propos de la ci-dessus:

1) les tests semblent courts, simples et faciles à comprendre, comme elles devraient être; s'ils semblent gros et laids comme ceux dans une autre réponse, vous faites quelque chose de fondamentalement mauvais.

2) le code de Test peut et doit avoir ses propres helpers d'infrastructure, tels que le IntegrationTests classe de base, qui va cacher n'importe quel accès JDBC/ORM méchant de la réelle test. J'ai mis en place de tels helpers dans plusieurs projets, donc je sais que cela peut être fait, mais ce serait des choses pour d'autres questions.

1
répondu Rogério 2015-02-08 16:12:29