Я пишу дополнительный ответ, потому что
- есть небольшая ошибка в решениях Тима относительно заголовка (но все же его ответ технически абсолютно верен!),
- вам не нужно
GroovySpy
здесь, просто Spy
абсолютно достаточно, - Я хочу показать вам альтернативный способ тестирования без заглушки
isEmpty()
, - Я хочу покажу вам, как вы можете использовать только одно взаимодействие с числом вызовов в троичном выражении вместо if-else (даже если отчеты об ошибках уродливы),
- Я хочу прокомментировать ваш способ тестирования в общие (см. конец этого поста).
package de.scrum_master.stackoverflow.q61032514;
import java.time.LocalDate;
public class DueDateEditor {
String text;
public boolean isEmpty() {
return text == null || text.trim() == "";
}
public void startEdit() {
if (!isEmpty())
callSuperStartEdit();
}
public void callSuperStartEdit() {}
}
package de.scrum_master.stackoverflow.q61032514
import spock.lang.Specification
import spock.lang.Unroll
class DueDateEditorTest extends Specification {
@Unroll
def 'super start edit #shouldMsg be called if the cell is #cellStateMsg'() {
given:
DueDateEditor editor = Spy() {
isEmpty() >> empty
}
when:
editor.startEdit()
then:
(empty ? 0 : 1) * editor.callSuperStartEdit()
where:
empty << [true, false]
shouldMsg = empty ? 'should not' : 'should'
cellStateMsg = empty ? 'empty' : 'not empty'
}
@Unroll
def "super start edit #shouldMsg be called if cell text is '#text'"() {
given:
DueDateEditor editor = Spy()
editor.text = text
when:
editor.startEdit()
then:
(editor.isEmpty() ? 0 : 1) * editor.callSuperStartEdit()
// Or, if 'isEmpty()' has a side effect:
// (text ? 1 : 0) * editor.callSuperStartEdit()
where:
text << ["foo", "", null, "line 1\nline 2"]
shouldMsg = text ? 'should' : 'should not'
cellStateMsg = text ? 'not empty' : 'empty'
}
}
Общие замечания:
- Я бы не проверял внутреннюю проводку одного класса с взаимодействиями , Тест будет хрупким, и если вы проведете внутреннюю реорганизацию класса, не изменив API вообще, тест может прерваться, если взаимодействия перестанут соответствовать ожидаемым. Я думаю, что это чрезмерная спецификация, и я бы использовал тестирование взаимодействия только для критически важных взаимодействий между различными классами или, возможно, разными экземплярами одного класса - «критическими», что означает такие вещи, как функциональность шаблонов проектирования, таких как Observer.
- Наличие if-else для дифференциации двух случаев по двум различным шаблонам взаимодействия, если весь тест знает только эти два случая, просто делает тест менее читаемым и более сложным, смотрите ваш собственный код, а также мой и Тим. В таком случае я бы предпочел написать два метода с простыми заголовками и простой функциональностью, но без if-else или троичных выражений, без вспомогательных переменных для заголовков et c.
PS: Извините, Мне нужно было создать тестовый класс DueDateEditor
, чтобы мой тест скомпилировался и работал как ожидалось. Как обычно, Майк, к сожалению, не предоставил MCVE , а только его часть.
Обновление: Мы говорили о GroovySpy
в наших комментариях и, как я уже сказал, он не будет работать, если ваши классы Java классы и есть конечный метод, который вы хотите заглушки, см. руководство Spock . Вот вам подтверждение:
package de.scrum_master.stackoverflow.q61032514;
public class TreeTableCell<A, B> {
String text;
public final boolean isEmpty() {
return text == null || text.trim() == "";
}
}
package de.scrum_master.stackoverflow.q61032514;
import java.time.LocalDate;
public class DueDateEditor extends TreeTableCell<String, LocalDate> {
public void startEdit() {
if (!isEmpty())
callSuperStartEdit();
}
public void callSuperStartEdit() {}
}
package de.scrum_master.stackoverflow.q61032514
import spock.lang.Specification
import spock.lang.Unroll
class DueDateEditorTest extends Specification {
@Unroll
def 'super start edit #shouldMsg be called if the cell is #cellStateMsg'() {
given:
DueDateEditor editor = GroovySpy() {
isEmpty() >> empty
}
when:
editor.startEdit()
then:
(empty ? 0 : 1) * editor.callSuperStartEdit()
where:
empty << [true, false]
shouldMsg = empty ? 'should not' : 'should'
cellStateMsg = empty ? 'empty' : 'not empty'
}
}
Тест сработал бы, если бы ваши классы приложений были только Groovy классами. Но если они являются Java классами, как в моем примере, тест не пройдёт так:
Too few invocations for:
(empty ? 0 : 1) * editor.callSuperStartEdit() (0 invocations)
Unmatched invocations (ordered by similarity):
1 * editor.startEdit()
methodName == "callSuperStartEdit"
| |
startEdit false
10 differences (44% similarity)
(s---------)tartEdit
(callSuperS)tartEdit
Так что в этом случае вы не можете просто использовать Groovy magi c для проверки взаимодействий. Но, как я уже сказал, ты не должен так поступать. Скорее убедитесь, что и startEdit()
, и callSuperStartEdit()
делают правильные вещи. Проверьте их результаты или, если они void
, проверьте их побочные эффекты на состояние испытуемого или его соавторов.
Обновление 2: Относительно вашего исходного вопроса Что касается именованных индексированных методов, на самом деле @ tim_yates дал правильный ответ. Я просто хочу добавить соответствующую ссылку на руководство Спока, объясняющую метод развертывания и как вы можете влиять на именование с помощью переменных из блока where:
.