Спок groovy - как издеваться над методами в одном классе? - PullRequest
0 голосов
/ 07 февраля 2020

Как смоделировать приватный метод и метод в другом классе в тестовом классе?

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;
    }

}

Ниже приведена моя текущая реализация для Спока, и я не уверен, как реализовать макет для объектов.

@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() метод здесь. Но метод процесса вызывает закрытый метод изнутри. Я хочу иметь возможность возвращать фиктивное значение для закрытого метода, а не выполнять закрытый метод.

Редактировать: Retriever и DataStore являются интерфейсами, а их соответствующими реализациями являются ScoreData и Model.

1 Ответ

3 голосов
/ 07 февраля 2020

Примечание: я только пытаюсь проверить метод 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

Но я говорю это снова: не делайте этого. Вместо этого убедитесь, что ваши введенные макеты показывают правильное поведение, чтобы вы могли фактически выполнять методы в тестируемом классе. Это то, о чем идет речь, не так ли?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...