如何在java中模拟单个语句

时间:2016-10-18 04:35:09

标签: java spring unit-testing mockito

我想使用Spring和JDBC实现数据库阅读器。

@Component
public class MyReader() {

    public void read() {
        /* Other code */

        ResultSet rs = stmt.executeQuery(sql);
        while(rs.next()){
            String myDbValue = rs.getString("myColumn");
        }

        /* Other code */
    }
}

如果列myColumn不存在,我想测试我的课程的行为。

一个解决方案是将常量myColumn移动到私有方法,但SO上的一些人告诉其他用户,嘲笑private methods smells,请参阅Raedwalds评论,我同意。 我也可以模拟数据库文件本身,但是mocking files isn't a good way too

任何想法如何处理这个问题?

1 个答案:

答案 0 :(得分:3)

您的测试代码,以及您选择模拟的内容和方式,与您正在测试的方法的功能有着内在和不可分割的联系。现在,这并不意味着它应该与该方法的实现相关联(您希望保持这种相当分离),但该方法的目的是做什么的核心目的是什么你应该测试。这就是精心设计,经过深思熟虑的测试推动良好API设计的原因。

您需要问自己的问题是 read方法在做什么?

我怀疑执行查询时返回的StatementResultSet都是您可以为测试目的而模拟的实现细节。

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.Matchers.*;

import java.sql.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MyReaderTest {

    @InjectMocks
    private MyReader myReader;

    @SuppressWarnings("unchecked")
    @Before
    public void setUp() throws Exception {
        Statement s = mock(Statement.class);
        ResultSet rs = mock(ResultSet.class);

        when(s.executeQuery(anyString())).thenReturn(rs);
        when(rs.getString("myColumn")).thenThrow(SQLException.class);
    }

    @Test
    public void testRead_AccessNonExistentColumn() {
        // Use mock statement and mock resultset
    }

}