Код вашего приложения выглядит очень странно. Стиль программирования в вашем унаследованном приложении настолько плох? Сначала создается объект DataService
с помощью конструктора без аргументов, который просто перезаписывается на следующем шаге путем вызова метода для этого экземпляра, который снова возвращает объект DataService
. Какой программист создает такой код? Или вы просто создали какой-то псевдокод, который не имеет ничего общего с вашим реальным приложением? Пожалуйста, объясните.
Что касается вашего тестового кода, он также не имеет смысла, потому что вы создаете экземпляр DataService mockObj
в качестве локальной переменной в своем методе объекта (методе теста), что означает, что в вашем вспомогательном методе mockObj
не могут быть доступныПоэтому вам нужно либо передать объект в качестве параметра вспомогательным методам, либо сделать его полем в вашем тестовом классе.
И последнее, но не менее важное: ваш локальный фиктивный объект никогда не вводится в класстестируется, потому что, как я сказал в первом абзаце, объект DataService
в getData()
также является локальной переменной. Если код вашего приложения не является полностью фальшивым, невозможно внедрить макет, потому что getData()
не имеет никакого параметра метода, а объект DataService
не является полем, которое может быть установлено с помощью метода или конструктора сеттера. Таким образом, вы можете создать столько макетов, сколько захотите, приложение никогда не будет о них знать. Таким образом, ваша заглушка findByOffset(long offset)
(почему вы не показываете код этого метода?) Не имеет никакого эффекта.
Итог: приведите пример, отражающий структуру вашего реального кода, как приложения, так и тестакод. Предоставленные вами фрагменты, к сожалению, не имеют никакого смысла. Я пытаюсь помочь, но так не могу.
Обновление:
В своих комментариях я упомянул рефакторинг вашего старого кода для тестируемости, добавив конструктор, метод установки или перегруженный метод getData
с дополнительным параметром. Вот пример того, что я имею в виду:
Класс вспомогательного помощника:
package de.scrum_master.stackoverflow.q58470315;
public class DataService {
private long offset;
public DataService(long offset) {
this.offset = offset;
}
public DataService() {}
public DataService findByOffset(long offset) {
return new DataService(offset);
}
public long getOffset() {
return offset;
}
@Override
public String toString() {
return "DataService{" +
"offset=" + offset +
'}';
}
}
Испытуемый объект:
Позвольте мне добавить приватный DataService
член с установщиком, чтобы сделать объект инъекционным. Я также добавляю проверку, был ли введен член ds
или нет. Если нет, то код будет работать так же, как и раньше, и сам создаст новый объект.
package de.scrum_master.stackoverflow.q58470315;
public class ToBeTestedWithInteractions {
private DataService ds;
public void setDataService(DataService ds) {
this.ds = ds;
}
// legacy code; can't alter
public void getData() {
if (ds == null)
ds = new DataService();
ds = ds.findByOffset(5);
Long len = ds.getOffset();
}
}
Тест Спока:
Теперь давайте проверим оба нормальныхи сценарий ошибки. На самом деле, я думаю, вам следует разбить его на два более мелких метода функций, но, как вы, похоже, хотите проверить все (слишком много IMO) в одном методе, вы также можете сделать это с помощью двух различных пар блоков when-then
. Вам не нужно явно объявлять какие-либо блоки взаимодействия для этого.
package de.scrum_master.stackoverflow.q58470315
import spock.lang.Specification
class RepeatedInteractionsTest extends Specification {
def "test scene1"() {
given: "subject under test with injected mock"
ToBeTestedWithInteractions subjectUnderTest = new ToBeTestedWithInteractions()
DataService dataService = Mock()
subjectUnderTest.dataService = dataService
when: "getting data"
subjectUnderTest.getData()
then: "no error, normal return values"
noExceptionThrown()
1 * dataService.findByOffset(5) >> dataService
1 * dataService.getOffset() >> 200
when: "getting data"
subjectUnderTest.getData()
then: "NPE, only first method called"
thrown NullPointerException
1 * dataService.findByOffset(5) >> null
0 * dataService.getOffset()
}
}
Обратите также внимание, что тестирование исключений, которые выдают или не выдает, добавляет значение к тесту w, тестирование взаимодействия просто проверяет внутренний устаревший кодповедение, которое мало что значит.