Недавно я попытался протестировать поведение повторных попыток в модульных тестах, настроив ложную зависимость, чтобы она возвращала несколько Mono.error () перед возвратом успешного завершения mono.just () в конце:
@Mock
Dependency dependency;
@InjectMocks
ClassUnderTest classUnderTest;
@Test
void someTest() {
final Object object = new Object();
when(dependency.method(anyString()))
.thenReturn(Mono.error(new Exception()))
.thenReturn(Mono.error(new Exception()))
.thenReturn(Mono.error(new Exception()))
.thenReturn(Mono.just(object));
StepVerifier.create(classUnderTest.method("abc"))
.expectNext(object)
.verifyComplete();
verify(dependency, times(4)).method("abc");
}
Вышеуказанная настройка не будет работать, как я выяснил позже, повторная попытка в Reactor не выполняется путем повторного вызова метода в течение определенного времени c, но путем однократного вызова метода, получения издателя и повторной подписки на него снова и снова.
class ClassUnderTest {
private Dependency dependency;
public Mono<Object> method(final String str) {
return this.dependency.method(str).retryWhen(Retry.max(3));
}
}
И повторная подписка не будет работать, если Dependency#method
реализован как:
class Dependency {
private OtherDependency otherDependency;
public Mono<Object> method(final String str) {
return this.otherDependency.get(str).map(/* some mapping logic */);
}
}
Dependency#method
не может сделайте слишком много предположений о том, будет ли OtherDependency#get
отложено или нет. Следовательно, Dependency
необходимо:
class Dependency {
private OtherDependency otherDependency;
public Mono<Object> method(final String str) {
return Mono.defer(() -> this.otherDependency.get(str)).map(/* some mapping logic */);
}
}
Поскольку мы хотим сказать, что каждый метод должен быть «повторяющимся», значит ли это, что нам нужно всегда использовать defer(...)
?
Или я что-то неправильно понимаю?