簡體   English   中英

Mocking 與 Spock 返回 null 嵌套 mocking 和存根

[英]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));
            // ...
        }
    }
}

Groovy Web 控制台試試

為了將來參考,我通過實際執行 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM