[英]Mocking with Spock returns null for nested mocking and stubbing
我正在使用 Spock 為一系列嵌套對象編寫單元測試。 我正在為其編寫測試的代碼非常遺留,不使用依賴注入。 然而,它也是非常關鍵的任務,所以除非我真的需要,否則我寧願不碰它。
這是我要測試的 class 的構造函數:
public SqlTable(Connection conn, String query) throws Exception {
this.statement = conn.createStatement();
this.resultSet = statement.executeQuery(query);
meta = resultSet.getMetaData();
int n = meta.getColumnCount();
columns = new Column[n];
for (int c = 0; c < n; c++) {
columns[c] = new Column(meta.getColumnName(c+1));
// ...
}
}
在測試中,我將嵌套模擬存根到.groovy
文件中,如下所示:
def "initialising a SQL table"() {
given:
def COL_NAME = "someColumnName"
def mockResSetMeta = Mock(ResultSetMetaData) {
getColumnCount() >> 1
getColumnName(_ as int) >> COL_NAME
}
and:
def mockResSet = Mock(ResultSet) {
getMetaData() >> mockResSetMeta
}
and:
def mockStatement = Mock(Statement) {
executeQuery(_ as String) >> mockResSet
}
and:
def mockConn = Mock(Connection) {
createStatement() >> mockStatement
}
when: "SqlTable object"
def table = new SqlTable(mockConn, "some query")
then: "the table contains the categorical column"
table.columns[0].getName() == COL_NAME
}
但是測試失敗。 通過調試,我發現,在SqlTable
構造函數中,當調用getColumnName()
時, ResultSetMetaData
object 的模擬總是返回null
。
我做了一些挖掘,這似乎是由於 Spock 如何一起處理存根和 mocking。 我在 SO 上找到了兩個有希望的答案:
然而,對於我的生活,我無法修改測試以使其工作。
問題在於這一行getColumnName(_ as int) >> COL_NAME
當您將其更改為getColumnName(_ as Integer) >> COL_NAME
或只是getColumnName(_) >> COL_NAME
時,它會起作用。
我目前關於為什么會發生這種情況的假設是模擬中的實際 arguments 作為Object[]
傳遞並且不能包含原始類型。
這是一個可運行的復制器
import spock.lang.*;
import java.sql.*;
class ASpec extends Specification {
def "initialising a SQL table"() {
given:
def COL_NAME = "someColumnName"
def mockResSetMeta = Mock(ResultSetMetaData) {
getColumnCount() >> 1
getColumnName(_ as Integer) >> COL_NAME
}
and:
def mockResSet = Mock(ResultSet) {
getMetaData() >> mockResSetMeta
}
and:
def mockStatement = Mock(Statement) {
executeQuery(_ as String) >> mockResSet
}
and:
def mockConn = Mock(Connection) {
createStatement() >> mockStatement
}
when: "SqlTable object"
def table = new SqlTable(mockConn, "some query")
then: "the table contains the categorical column"
table.columns[0].getName() == COL_NAME
}
}
@groovy.transform.Canonical
class Column {
String name
}
class SqlTable {
def columns
public SqlTable(Connection conn, String query) throws Exception {
def statement = conn.createStatement();
def resultSet = statement.executeQuery(query);
def meta = resultSet.getMetaData();
int n = meta.getColumnCount();
columns = new Column[n];
for (int c = 0; c < n; c++) {
columns[c] = new Column(meta.getColumnName(c+1));
// ...
}
}
}
為了將來參考,我通過實際執行 mocking 而不僅僅是存根來輕松檢測到問題。
then:
1 * mockResSetMeta.getColumnName(_ as int) >> COL_NAME
將打印
1 * mockResSetMeta.getColumnName(_ as int) >> COL_NAME (0 invocations)
Unmatched invocations (ordered by similarity):
1 * mockResSetMeta.getColumnName(1)
One or more arguments(s) didn't match:
0: argument instanceof int
| | |
| false int
1 (java.lang.Integer)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.