Примечание: я только пытаюсь проверить метод process()
здесь. Но метод процесса вызывает закрытый метод изнутри. Я хочу иметь возможность возвращать фиктивное значение для приватного метода, а не выполнять приватный метод.
Вы не должны этого делать, потому что MyClass
- ваш тестируемый класс. Вы не можете покрыть логи c внутри приватных методов тестами, если заглушите их. Вместо этого вы должны убедиться, что внедренные макеты ведут себя так, как вы хотите (через методы-заглушки), если они используются внутри этого закрытого метода. К сожалению, вы решили не показывать эту важную часть вашего кода, хотя от него зависит точный ответ. Вместо этого вы заменили их комментариями «некоторая бизнес-логика c», что не очень полезно, потому что ваша бизнес-логика c - это то, что вы хотите проверить. Вы не хотите заглушить это.
Поэтому, пожалуйста, не делайте того, что я вам здесь показываю, я отвечаю только потому, что вы спросили.
Для того, чтобы заглушить метод, он не должен быть закрытым, потому что шпионы, издевательства или заглушки технически всегда являются подклассами, или оригиналы и подклассы не могут наследовать или даже вызывать частные методы. Таким образом, вам нужно сделать методы защищенными (чтобы их могли использовать или переопределить подклассы) или с областью действия пакета. Я рекомендую первый.
Но вы не можете использовать обычный макет или заглушку в качестве замены для тестируемого класса, потому что вы хотите только заглушить часть бизнес-логики c (ваши два метода в вопрос), а не весь лог c (хотите сохранить 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
Но я говорю это снова: не делайте этого. Вместо этого убедитесь, что ваши введенные макеты показывают правильное поведение, чтобы вы могли фактически выполнять методы в тестируемом классе. Это то, о чем идет речь, не так ли?