如果存在多种方法,则如何模拟局部变量

时间:2019-07-11 12:32:15

标签: junit mockito

我是Mockito和Junit的新手。 在添加现有类的测试时遇到麻烦。

我正在使用以下2种方法上课。 privateMethod和public方法 Publicmethod调用私有方法,并且在功能上与私有方法具有相似的结构(即从DB中获取一些东西)

现在,通过模仿测试时,我正在尝试这样做

    Class MyClass {
        private String privateMethod(String number){
            String sql = null;
            java.sql.Connection conn = null;
            PreparedStatement pst = null;
            ResultSet rs1 = null;
            String returnString = "";
            try {
                conn = dbConnect();
                sql = " Select SomeCOL from SOME_TABLE";
                pst = conn.prepareStatement(sql);
                pst.setString(1, caseNumber);
                rs1 = pst.executeQuery();
                if(rs1.next())
                    returnString = rs1.getString(1);
            }catch (SQLException e) {
            } finally {
                //close conn
            }
            return returnString ;
        }
        public void publicmethod(String number){
            String retVal = privateMethod(number);
            if(!StringUtils.isEmpty(retVal)){
                String sql = null;
                java.sql.Connection conn1 = null;
                PreparedStatement pst = null;
                ResultSet rs1 = null;
                try {
                    conn1 = dbConnect();
                    sql = " SOME_SQL_STMNT";
                    pst = conn1.prepareStatement(sql);
                    rs1 = pst.executeQuery();
                    while(rs1.next()){
                                     //do something
                    }
                }catch (SQLException e) {
                } finally {
                    //close conn
                }
            }   

        }
    }

下面是 Test class : 添加了donothing以跳过对dbdisconnect方法的调用,该方法将null分配给conn(将模拟连接更改为null)

    Class MyclassTest {
    @InjectMocks
        private MyClass mc;

        @Mock
        java.sql.Connection mockConn;

        @Mock private PreparedStatement mockStatement;

        @Mock
        ResultSet rs;


        @Before
        public void setup(){
            MockitoAnnotations.initMocks(this);
        }
        try {

                when(mockConn.prepareStatement(" Select SomeCOL from SOME_TABLE")).thenReturn(mockStatement);
    when(mockStatement.executeQuery()).thenReturn(rs));
                when(rs.next()).thenReturn(true).thenReturn(false);
                when(rs.getString(1)).thenReturn("123");
            } catch (SQLException e) {
            }

现在,当我运行这些测试时,我可以看到Connection在privatemethod上被嘲笑了,并且我看到返回的值是“ 123”(尝试抛出带有消息作为returnvalue的手动异常)。但是在公开方法中,我得到

  

行的空指针   pst = conn1.prepareStatement(sql);   因为conn1为空。

有什么问题吗? 我们可以处理吗?

具有Dbconnect方法的MyClass超级类的更新代码

public java.sql.Connection dbConnect (String dbname) {
        DSname = "SOME_DSLOOKUPNAME";
        InitialContext ctx = null;
        if (connection == null) {
            try {
                Hashtable<String, String> ht = new Hashtable<>();
                ht.put(Context.PROVIDER_URL, "PROVIDER_PORT");
                ctx = new InitialContext(ht);
                javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup(DSname);
                connection = ds.getConnection();
            } catch (Exception e) {
            }
        }
        return (connection);
    }

最终工作测试实施

Class MyclassTest {
@InjectMocks
    private MyClass mc;

    @Mock
    java.sql.Connection mockConn;

    @Mock private PreparedStatement mockStatement;

    @Mock
    ResultSet rs;
@Spy
MyClass mc1;



    @Before
    public void setup(){
        MockitoAnnotations.initMocks(this);
    }
@Test
public void publicMethodTest(){
    try {
           Mockito.doReturn(mockConn).when(mc1).dbConnect(Mockito.anyString());
        when(mockConn.prepareStatement(Mockito.anyString())).thenReturn(mockStatement).thenReturn(mockStatement);
        doNothing().when(mc1).dbDisconnect();

        when(mockStatement.executeQuery()).thenReturn(rs).thenReturn(rs);
        when(rs.next()).thenReturn(true).thenReturn(true).thenReturn(false);
        when(rs.getString(1)).thenReturn("123");
        } catch (SQLException e) {
        }
mc1.publicMethod("12345678");
}

2 个答案:

答案 0 :(得分:1)

我认为您需要一种通过某种构造函数或setter方法在MyClass中注入连接对象的方法。这样你就可以嘲笑。

public class  MyClass {
private Connection connection;

public MyClass(Connection connection) {
  this.connection = connection;
}
....
....

}

在单元测试中,您可以模拟这样的事情:

    @Test
    public void testConnection() {
    Connection mockConnection = mock(Connection.class);
    when(mockConnection.prepareStatment("select statements")).thenReturn(mockStatement);
     MyClass myClass = new MyClass(mockConnection);
    myClass.publicMethod();
 }

答案 1 :(得分:0)

prepareStatementprivateMethod()中使用不同的参数值调用方法publicMethod()。因此,您应该:

分别模拟每个呼叫:

when(mockConn.prepareStatement(" Select SomeCOL from SOME_TABLE")).thenReturn(mockStatement);
when(mockConn.prepareStatement(" SOME_SQL_STMNT")).thenReturn(mockStatement);

或者有一个更通用的模拟:

when(mockConn.prepareStatement(Mockito.anyString())).thenReturn(mockStatement);