[英]Spock groovy - how to mock methods in same class?
如何在測試類中模擬不同類中的私有方法和方法?
class MyClass {
private final Retriever<ScoreData> retriever;
private DataStore<Model> dataStore;
private String gameName;
public void MyClass(Retriever<ScoreData> retriever, DataStore<Model> dataStore, String gameName) {
this.retriever = retriever;
this.dataStore = dataStore;
this.gameName = gameName;
}
public void process(GameHolder<G> games) {
// Business Logic
for (Game<G> game : games){
Integer score = game.getScore();
Integer playerId = game.getPlayerId();
Integer finalScore = getScore(game);
computeScore(score, finalScore);
}
}
private Integer computeScore(int score, int finalScore) {
// Runs some business logic and returns O3
return score + finalScore;
}
private Integer getScore(Game game) {
// Runs some business logic and returns O3
String dbName = game.getDbName();
DBRetriever ret = new DBRetriever(dbName)
if (dbName.equals("gameDB"){
return ret.getFinalScore(dbName);
}
return -1;
}
}
下面是我當前對 Spock 的實現,我不確定如何實現對象的模擬。
@Subject
def obj
def "this is my test"(){
given:
Object1 obj1 = Mock(Object1)
Object2 obj2 = Mock(Object2)
Object3 obj3 = Mock(Object3)
def myClassObject = new MyClass(obj1, obj2, obj3)
when:
myClassObject.process(new Object4())
then:
1 * getScore()
1 * computeScore()
}
如何模擬 computeScore 和 getScore 函數以及如何為對象 obj1、obj2、obj3 分配初始值?
注意:我只是想在這里測試process()
方法。 但是 process 方法正在從內部調用私有方法。 我希望能夠為私有方法返回一個模擬值,而不是執行私有方法。
編輯:Retriever 和 DataStore 是接口,它們各自的實現是 ScoreData 和 Model。
注意:我只是想在這里測試
process()
方法。 但是 process 方法正在從內部調用私有方法。 我希望能夠為私有方法返回一個模擬值,而不是執行私有方法。
您不應該這樣做,因為MyClass
是您正在測試的班級。 如果你存根測試,你就不能用測試覆蓋私有方法中的邏輯。 相反,如果注入的模擬在這些私有方法中使用,您應該確保它們按照您希望的方式運行(通過存根方法)。 不幸的是,您決定不顯示代碼的關鍵部分,即使確切的答案取決於它。 相反,您將它們替換為注釋“一些業務邏輯”,這不是很有幫助,因為您的業務邏輯是您要測試的內容。 你不想把它存起來。
所以請不要做我在這里展示給你的東西,我只是因為你問了才回答。
為了存根方法,它不能是私有的,因為從技術上講,間諜、模擬或存根始終是子類,或者原始和子類不能繼承甚至調用私有方法。 因此,您需要使方法受保護(以便子類可以使用或覆蓋它們)或包作用域。 我推薦前者。
但是您不能使用普通的模擬或存根作為被測類的替代品,因為您只想刪除部分業務邏輯(您有問題的兩個方法),而不是整個邏輯(您想保留process()
)。 因此,您需要一個部分模擬。 為此,您可以使用間諜。
虛擬依賴類:
package de.scrum_master.stackoverflow.q60103582;
public class Object1 {}
package de.scrum_master.stackoverflow.q60103582;
public class Object2 {}
package de.scrum_master.stackoverflow.q60103582;
public class Object3 {}
package de.scrum_master.stackoverflow.q60103582;
public class Object4 {}
被測類:
package de.scrum_master.stackoverflow.q60103582;
public class MyClass {
private Object1 o1;
private Object2 o2;
private Object3 o3;
public MyClass(Object1 o1, Object2 o2, Object3 o3) {
this.o1 = o1;
this.o2 = o2;
this.o3 = o3;
}
public void process(Object4 o4) {
System.out.println("process - business Logic");
Object2 result = getScore("dummy ID");
Object3 obj = computeScore(result);
}
protected Object3 computeScore(Object2 result) {
System.out.println("computeScore - business logic");
return o3;
}
protected Object2 getScore(String id) {
System.out.println("getScore - business logic");
return o2;
}
}
斯波克測試:
package de.scrum_master.stackoverflow.q60103582
import spock.lang.Specification
class MyClassTest extends Specification {
def "check main business logic"(){
given:
Object1 obj1 = Mock()
Object2 obj2 = Mock()
Object3 obj3 = Mock()
MyClass myClass = Spy(constructorArgs: [obj1, obj2, obj3])
when:
myClass.process(new Object4())
then:
1 * myClass.getScore(_) //>> obj2
1 * myClass.computeScore(_) //>> obj3
}
}
在這里你可以看到如何檢查間諜的交互。 但請注意, computeScore(_)
和getScore(_)
仍然會被執行,正如您在控制台日志中看到的:
process - business Logic
getScore - business logic
computeScore - business logic
如果取消注釋最后兩行代碼的結尾
1 * myClass.getScore(_) >> obj2
1 * myClass.computeScore(_) >> obj3
您實際上將避免完全執行這兩個(受保護的)方法並用存根結果替換它們。 控制台日志將更改為:
process - business Logic
但我要再說一遍:不要這樣做。 相反,請確保您注入的模擬顯示正確的行為,以便您可以實際執行被測類中的方法。 這就是測試的意義,不是嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.