我是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");
}
答案 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)
在prepareStatement
和privateMethod()
中使用不同的参数值调用方法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);