Учитывая мои комментарии к вышеупомянутому вопросу, я думаю, что вам лучше использовать голый Mockito здесь (без Спока, как вы спросили в комментариях, когда я изо всех сил пытаюсь сделать читабельную спецификацию Спока для этого варианта использования):
РЕДАКТИРОВАТЬ: Полностью правильное решение ниже этого
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DCSTest.SpringRetryConfig.class)
public class DCSTest {
@Autowired
private DCS dcs;
@Test
public void test_retry() {
//given:
LComponent component = mock(LComponent.class);
DataCollectionDataSet dataSet = mock(DataCollectionDataSet.class);
given(dcs.execute(component, dataSet)) //It's BDDMockito class
.willThrow(new RuntimeException("1"))
.willThrow(new RuntimeException("2"))
.willReturn("Foo");
//when:
String result = dcs.execute(component, dataSet);
//then:
verify(dcs, times(3)).execute(component, dataSet);
assertThat(result, equalTo("Foo"));
}
@Configuration
@EnableRetry
static class SpringRetryConfig {
@Bean
DCS dcs() {
return mock(DCS.class);
}
}
}
public class DCS {
@Retryable(maxAttempts = 3)
String execute(LComponent component, DataCollectionDataSet dataSet) {
return "Bar";
}
}
ПРАВИЛЬНОЕ РЕШЕНИЕ:
Хорошо, какОП и обнаруженный выше verify(dcs, times(3)).execute(component, dataSet);
не работает должным образом.Независимо от того, какое число вы используете в times()
, тест всегда будет успешным.Это потому, что @Retryable
создает аспект вокруг макета dcs
.В результате каждый вызов dcs.execute
перехватывается Spring, и Mockito фактически не проверяет вызов.Чтобы преодолеть это, мы можем создать собственный аспект вокруг макета и просто в качестве побочного эффекта посчитать, сколько раз вызывается метод @Retryable
.Ниже приведен рабочий код такого решения:
@RunWith(SpringJUnit4ClassRunner.class)
public class DCSTest {
@Autowired
private LComponent component;
@Autowired
private DataCollectionDataSet dataSet;
@Autowired
private DCS dcs;
@Autowired
private RetryCount retryCount;
@Test
public void test_retry() {
//when:
String result = dcs.execute(component, dataSet);
//then:
assertThat(retryCount.value, equalTo(3));
assertThat(result, equalTo("Foo"));
}
@Aspect
public static class RetryCount {
public int value = 0;
@Before("execution(* DCS.execute(..))")
public void advice() {
value++;
}
}
@Configuration
@EnableRetry
@EnableAspectJAutoProxy
public static class SpringRetryConfig {
@Bean
DCS dcs() {
DCS dcs = mock(DCS.class);
given(dcs.execute(component(), dataSet())) //It's BDDMockito class and take note that better to keep this declaration here so that Spring doesn't intercept the call once Retryable aspect is created
.willThrow(new RuntimeException("1"))
.willThrow(new RuntimeException("2"))
.willReturn("Foo");
return dcs;
}
@Bean
RetryCount retryCount() {
return new RetryCount();
}
@Bean
LComponent component() {
return new LComponent();
}
@Bean
DataCollectionDataSet dataSet() {
return new DataCollectionDataSet();
}
}
}