![](/img/trans.png)
[英]Mocked instance of final class in Spock behaves differently in test and dev code
[英]Mocked java class in spock test is not being executed
我正在嘗試使用spock框架對一些Java類進行單元測試。 結構如下:
com.myorg.requests
(類名: RequestProcessor
) com.myorg.query
(類名: DatabaseQuery
) 第一類看起來像這樣:
public class RequestProcessor {
private String request;
public RequestProcessor(String aRequest) {
this.request = request;
}
public String processRequest() {
String response ;
//do something here
try {
if(condition meets) {
response = executeRequest();
}
} catch ( various exceptions... ) {
System.out.println("something went wrong...");
}
}
private String executeRequest() throws <<exceptions thrown by DatabaseQuery>> {
//do something here
DatabaseQuery queryResult = new DatabaseQuery(request)
}
}
我正在嘗試為此RequestProcessor
類編寫一個Spock測試,它依賴於DatabaseQuery
。 我正在考慮模擬DatabaseQuery
類,以便簡單地RequestProcessor
測試RequestProcessor
類。
正在調用RequestProcessor
的processRequest()
方法,該方法依賴於另一個私有方法。 該方法將使用DatabaseQuery
獲取實際的查詢結果。 這是我的Spock測試的樣子:
class RequestProcessorSpec extends Specification {
//Class to be tested
RequestProcessor requestProcessor
//Dependencies
DatabaseQuery dbquery
def "Given a valid request, dbquery's executeQuery method is called" () {
given: "a valid request"
def queryRequest = '{"info1":"value1","info2":"value2","query":"select * from users"}'
and: "mock the DBQuery class"
dbquery = Mock(DatabaseQuery)
and: "create a new request"
requestProcessor = new RequestProcessor(queryRequest)
when: "the request is processed"
requestHandler.processRequest()
then: "dbquery executeQuery method is called"
1 * dbquery.executeQuery(_ as String)
}
}
這並不適合我。 我收到一個錯誤:
當我使用gradlew test --info
運行測試以獲取更多結果時,我看到控制台上打印了一條日志,該日志由processRequest
方法中的try-catch語句捕獲。
我在這里做錯了什么?
首先,即使我簡化了示例代碼並創建了自己的虛擬DatabaseQuery
類,您的示例代碼也無法正常工作,因為這里至少有三個錯誤:
this.request = request
(自我分配),但應為this.request = aRequest;
。 requestHandler.processRequest()
,但應為requestProcessor.processRequest()
。 executeRequest()
不返回指定的String
。 所以我只能推測,實際上它在DatabaseQuery
調用了另一個方法,以便將查詢結果轉換為String
。 弄清楚了這一點之后,讓我們看看您的測試真正存在的根本錯誤。
我在這里做錯了什么?
假定本地變量中的模擬對應用程序代碼中的其他本地變量某種程度上有效。 為了使用模擬,您需要將其注入到測試中的類中。 但是,與許多開發人員一樣,您並不是通過依賴注入來設計去耦和可測試性,而是在內部創建依賴關系(在本例中為DatabaseQuery
對象)。
我認為您的測試只會遭受規格過高的困擾。 您為什么要檢查是否從私有方法中調用了另一個類中的特定方法(間接)? 您沒有直接測試私有方法,而是通過調用公共方法覆蓋了它們的代碼,而您的測試已經做到了。
如果您想掩蓋catch
,只需確保您的請求導致正確的例外。 也許您需要為此模擬數據庫連接,並確保它將預期結果返回到DatabaseQuery
。 為了准確地說,我看不到足夠多的代碼。
現在,讓我們假設無論我之前說什么,您都絕對要檢查此交互。 您需要執行的操作取決於情況(您的代碼中未顯示):
無論如何,您都需要使DatabaseQuery
可注入。 您可以將一個成員和另一個設置器添加到您的班級。
現在,您將有一個分支,這取決於從以下位置進行交互dbquery.executeQuery(_ as String)
位置(稱為):
DatabaseQuery
外部調用該方法,則可以注入普通的Mock
。 DatabaseQuery
內部調用該方法,則您需要注入一個Spy
因為模擬不會調用其他內部方法(如原始對象),因為-好的,它只是一個模擬。 情況1:從外部調用executeQuery(String)
package de.scrum_master.query;
public class DatabaseQuery {
private String request;
public DatabaseQuery(String request) {
this.request = request;
}
public String executeQuery(String request) {
return request.toUpperCase();
}
public String getResult() {
return executeQuery(request);
}
}
package de.scrum_master.requests;
import de.scrum_master.query.DatabaseQuery;
public class RequestProcessor {
private String request;
private DatabaseQuery databaseQuery;
public RequestProcessor(String aRequest) {
this.request = aRequest;
databaseQuery = new DatabaseQuery(request);
}
public String processRequest() {
return executeRequest();
}
private String executeRequest() {
return databaseQuery.executeQuery(request);
//return databaseQuery.getResult();
}
public void setDatabaseQuery(DatabaseQuery databaseQuery) {
this.databaseQuery = databaseQuery;
}
}
package de.scrum_master.requests
import de.scrum_master.query.DatabaseQuery
import spock.lang.Specification
class RequestProcessorTest extends Specification {
//Class to be tested
RequestProcessor requestProcessor
//Dependencies
DatabaseQuery dbquery
def "Given a valid request, dbquery's executeQuery method is called" () {
given: "a valid request"
def queryRequest = '{"info1":"value1","info2":"value2","query":"select * from users"}'
and: "mock the DBQuery class"
dbquery = Mock(DatabaseQuery)
//dbquery = Spy(DatabaseQuery, constructorArgs: [queryRequest])
and: "create a new request"
requestProcessor = new RequestProcessor(queryRequest)
requestProcessor.databaseQuery = dbquery
when: "the request is processed"
requestProcessor.processRequest()
then: "dbquery executeQuery method is called"
1 * dbquery.executeQuery(_ as String)
}
}
現在,該測試工作包括交互檢查。
情況2:從自己的類內部調用executeQuery(String)
您是否在RequestProcessor
和RequestProcessorTest
看到兩條注釋掉的行? 只需使用它們並注釋掉其他兩個即可,如下所示:
private String executeRequest() {
//return databaseQuery.executeQuery(request);
return databaseQuery.getResult();
}
and: "mock the DBQuery class"
//dbquery = Mock(DatabaseQuery)
dbquery = Spy(DatabaseQuery, constructorArgs: [queryRequest])
該測試仍然有效,包括交互檢查。
當然,我必須偽造一些東西,並填寫您沒有提供的缺少的拼圖塊,但這基本上就是它的工作原理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.