如何使用Mockito测试DAO方法?

我已经开始发现Mockito图书馆了,有一个问题,我找不到合适的答案。

如果我在我的UserDAO类中有这样的方法,可以将用户保存在数据库中:

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); } } .... } 

我该怎么测试呢?

如果我想测试例如DAO类,那么我需要创建一个DataSource模拟, Connection模拟, ResultSet模拟等? 那么不要测试数据库本身?

但是,如果我还想测试dao和数据库的行为怎么办?

您能否生成一些代码示例,可能有用的链接并显示最佳方法?

使用Mockito测试您的UserDAO是一个很好的开始。 此代码使用了大量的Mockitofunction,因此您可以看到如何使用它们。 如果您有疑问,请告诉我。

 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; } } } 

但是,如果我还想测试dao和数据库的行为怎么办?

如果你确实想要测试数据库(正如你所希望的那样!),那就没办法 – 你需要一个真正的数据库。 虽然是一个很棒的图书馆,Mockito可能是这项工作的错误工具。

像DBUnit这样的工具结合JUnit可以帮助您使用数据库测试DAO。 DBUnit可帮助您在UnitTest之前将测试数据插入数据库,并将数据库中的数据与测试后的预期进行比较。

这是你应该如何测试它:

 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(); } } 

关于上述的一些注意事项:

1)测试看起来简短,易于理解, 应该如此 ; 如果他们看起来像另一个答案那样大而丑,你做的事情根本就是错误的。

2)测试代码可以并且应该有自己的基础结构助手,例如IntegrationTests基类,它将隐藏实际测试中任何讨厌的JDBC / ORM访问。 我在几个项目中实现了这样的帮助,所以我知道这可以做到,但那将是其他问题的东西。