44import static org .assertj .core .api .Assertions .assertThatThrownBy ;
55import static org .mockito .ArgumentMatchers .any ;
66import static org .mockito .ArgumentMatchers .anyString ;
7- import static org .mockito .Mockito .times ;
7+ import static org .mockito .Mockito .atLeast ;
88import static org .mockito .Mockito .verify ;
99import static org .mockito .Mockito .when ;
1010
@@ -122,8 +122,27 @@ void shouldOpenCircuitWhen50PercentFailure() {
122122 @ Test
123123 @ DisplayName ("Circuit OPEN 상태에서는 예외가 발생한다" )
124124 void shouldThrowExceptionWhenCircuitOpen () {
125- // given - Circuit을 강제로 OPEN 상태로 만듦
126- circuitBreaker .transitionToOpenState ();
125+ // given - PG 실패를 발생시켜 Circuit을 OPEN 상태로 만듦
126+ when (pgClient .requestPayment (anyString (), any (PgPaymentRequest .class )))
127+ .thenThrow (createFeignException ());
128+
129+ // 슬라이딩 윈도우 10개 중 6개 이상 실패 시켜서 Circuit OPEN (실패율 50% 초과)
130+ for (int i = 0 ; i < 6 ; i ++) {
131+ try {
132+ paymentService .requestPayment (
133+ "user-" + i ,
134+ "order-fail-" + i ,
135+ BigDecimal .valueOf (10000 ),
136+ "SAMSUNG" ,
137+ "1234-5678-9012-3456"
138+ );
139+ } catch (Exception ignored ) {
140+ // 실패 예상
141+ }
142+ }
143+
144+ // Circuit이 OPEN 상태인지 확인
145+ assertThat (circuitBreaker .getState ()).isEqualTo (CircuitBreaker .State .OPEN );
127146
128147 // when & then - Circuit이 OPEN이면 예외 발생
129148 assertThatThrownBy (() -> paymentService .requestPayment (
@@ -134,8 +153,9 @@ void shouldThrowExceptionWhenCircuitOpen() {
134153 "1234-5678-9012-3456"
135154 )).isInstanceOf (Exception .class );
136155
137- // PG 호출이 없어야 함 (Circuit이 열려있으므로)
138- verify (pgClient , times (0 )).requestPayment (anyString (), any (PgPaymentRequest .class ));
156+ // Circuit이 OPEN이므로 마지막 호출은 차단됨
157+ // Retry가 있어서 정확한 횟수는 다를 수 있음 (최소 6번 이상 호출됨)
158+ verify (pgClient , atLeast (6 )).requestPayment (anyString (), any (PgPaymentRequest .class ));
139159 }
140160
141161 @ Test
0 commit comments