如何使用 Mockito 测试我的 DAO 方法?

Posted

技术标签:

【中文标题】如何使用 Mockito 测试我的 DAO 方法?【英文标题】:How to test my DAO methods using Mockito? 【发布时间】:2018-11-14 17:13:45 【问题描述】:

我正在尝试为我的 DAO 编写一些测试。我在这里遵循了一些教程/答案,但其中大多数不适用于我的 DAO。

示例代码:尝试根据给定的选择器()从数据库中获取选举。

public class AdminDaoImpl extends DaoImpl implements AdminDao 

    private final Logger LOGGER = Logger.getLogger(getClass().getName());

    @Override
    public ElectionListResponse getElections(char selector) 
        ElectionListResponse electionListResponse = new ElectionListResponse();

        String query = NamedQueries.GET_ELECTIONS_BEGIN + selector + NamedQueries.GET_ELECTIONS_END;

        try 
            con = sqlConnection.getConnection();
            stmt = con.prepareStatement(query);
            rs = stmt.executeQuery();

            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");

            while (rs.next()) 
                Election election = new Election();
                election.setElectionID(rs.getInt("id"));
                election.setElectionName(rs.getString("name"));
                election.setStartDate(df.format(rs.getDate("startDate")));
                election.setEndDate(df.format(rs.getDate("endDate")));
                electionListResponse.addElection(election);
            
            return electionListResponse;
         catch (SQLException e) 
            LOGGER.log(Level.SEVERE, "Cant get elections. ", e);
         finally 
            closeConnection();
        
        return null;
    

这是上面代码扩展的 DAO:

public abstract class DaoImpl implements Dao 

    private final Logger LOGGER = Logger.getLogger(getClass().getName());

    @Inject
    public SQLConnection sqlConnection;

    public Connection con;
    public PreparedStatement stmt;
    public ResultSet rs;

    public void closeConnection() 
        try 
            if (con != null) con.close();
            if (stmt != null) stmt.close();
            if (rs != null) con.close();
         catch (SQLException e) 
            LOGGER.log(Level.SEVERE, "Can't close connection with database. ", e);
        
    

我尝试应用一些我在网上找到的代码,这是我目前拥有的:

@RunWith(MockitoJUnitRunner.class)
public class AdminDaoImplTest 

    @Mock
    DataSource mockDataSource;
    @Mock
    Connection mockConn;
    @Mock
    PreparedStatement mockPreparedStmnt;
    @Mock
    ResultSet mockResultSet;

    @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.executeQuery()).thenReturn(mockResultSet);
        when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE);
    

    @After
    public void tearDown() 
    

    @Test
    public void testCreateWithNoExceptions() throws SQLException 

        ElectionListResponse electionListResponse = new ElectionListResponse();

        AdminDaoImpl instance = new AdminDaoImpl();
        instance.getElections('>' );

        //verify and assert
        verify(mockConn, times(1)).prepareStatement(anyString(), anyInt());
        verify(mockPreparedStmnt, times(1)).execute();
        verify(mockConn, times(1)).commit();
        verify(mockResultSet, times(2)).next();
        verify(mockResultSet, times(1)).getInt("id");
        verify(mockResultSet, times(1)).getString("name");
        verify(mockResultSet, times(1)).getDate("startDate");
        verify(mockResultSet, times(1)).getDate("endDate");
    



我应该如何测试它?您能提供一些代码示例吗?提前致谢!

空指针:

java.lang.NullPointerException
    at org.han.ica.oose.sneeuwklokje.database.admin.AdminDaoImpl.getElections(AdminDaoImpl.java:28)
    at org.han.ica.oose.sneeuwklokje.database.admin.AdminDaoImplTest.testGetElectionsNoExceptions(AdminDaoImplTest.java:77)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

【问题讨论】:

见:***.com/a/46206974/1100135 【参考方案1】:

您应该在测试中添加以下字段:

@InjectMocks
private AdminDaoImpl

这将在你的类中注入模拟,允许你进行测试。

你得到的 NullPointerException 可以通过这种方式修复(在测试类中):

@Mock
private SQLConnection mockSqlConnection;

在设置方法中添加:

when(mockSqlConnection.getConnection()).thenReturn(mockConn);

【讨论】:

你能发布堆栈跟踪吗? 已编辑帖子! 好像你有一个空记录器......你应该调试你的代码以了解什么是空并抛出 NullPointerException。 它指向: con = sqlConnection.getConnection();在 AdminDaoImpl 类中。难道是因为道延?如果是这样,我该如何解决这个问题,因为我不知道...... 让我们continue this discussion in chat。

以上是关于如何使用 Mockito 测试我的 DAO 方法?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JUnit 和 Mockito 对 DAO 类进行单元测试

Android 应用测试 - 如何使用真实数据库测试 DAO 层?

为啥嘲笑 DAO 时 mockito 崩溃?

如何使用 mockito 模拟方法?

Mock 模拟测试简介及 Mockito 使用入门

Mock测试框架(Mockito为例)