Неразрешенная зависимость в UnitTesting Spring Boot - PullRequest
0 голосов
/ 09 марта 2020

Я получаю следующую ошибку при попытке написать модульный тест для примера кода CircuitBreaker.

org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка создания компонента с именем com.foosball.team .Service.TeamServiceUnitTest ': неудовлетворенная зависимость, выраженная через поле' registry '; вложенное исключение - org.springframework.beans.factory.NoSuchBeanDefinitionException: нет доступного квалифицированного компонента типа 'io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry': ожидается, что по крайней мере 1 компонент будет квалифицирован как кандидат для автоматической передачи. Аннотации зависимостей: {@ org.springframework.beans.factory.annotation.Autowired (обязательно = true)}

TeamService:

@Service
public class TeamService {

    @Autowired
    private ITeamRepository teamRepository;

    @Autowired
    private PlayerClient playerClient;

    Logger logger = LoggerFactory.getLogger(TeamService.class);
    .
    .
    .

TeamServiceUnitTest:

@SpringBootTest(classes = {
        TeamService.class
})
@RunWith(SpringRunner.class)
@DirtiesContext
public class TeamServiceUnitTest extends AbstractCircuitBreakerTest {

    @MockBean
    private ITeamRepository teamRepository;

    @MockBean
    private PlayerClient playerClient;

    @Autowired
    private TeamService service;

    private TeamEntity teamEntity;

    private Logger logger = LoggerFactory.getLogger(TeamServiceUnitTest.class);

    @Before
    public void setUp(){
        teamEntity = new TeamEntity();
        teamEntity.setId(1L);
        teamEntity.setPlayerOne("One");
        teamEntity.setPlayerTwo("Two");
        teamEntity.setPlayerThree("Three");
        teamEntity.setPlayerFour("Four");
    }

    @Test
    @DisplayName("when Player Client Fails 11 Times Then CircuitBreaker Should Be In OPEN State")
    public void whenPlayerClientFailsElevenTimesThenCircuitBreakerShouldBeInOPENState(){
        //Given
        when(teamRepository.findAll()).thenReturn(new ArrayList<>());
        when(playerClient.get(Mockito.anyString())).thenThrow(new RuntimeException());


        //When
        for(int i=0; i<11; i++){
            try {
                service.addTeam(teamEntity);
            } catch (Exception ignore) {
                logger.info(ignore.getClass().getName());
            }
        }

        //Then
        checkHealthStatus(BACKEND_B, CircuitBreaker.State.OPEN);
    }

}

Ссылочный класс:

public class AbstractCircuitBreakerTest {

    protected static final String BACKEND_A = "backendA";
    protected static final String BACKEND_B = "playerClientCircuitBreaker";

    @Autowired
    protected CircuitBreakerRegistry registry;

    @Before
    public void setup(){
        transitionToClosedState(BACKEND_A);
        transitionToClosedState(BACKEND_B);
    }

    protected void checkHealthStatus(String circuitBreakerName, CircuitBreaker.State state) {
        CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
        assertThat(circuitBreaker.getState()).isEqualTo(state);
    }

    protected void transitionToOpenState(String circuitBreakerName) {
        CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
        if(!circuitBreaker.getState().equals(CircuitBreaker.State.OPEN)){
            circuitBreaker.transitionToOpenState();
        }
    }

    protected void transitionToClosedState(String circuitBreakerName) {
        CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
        if(!circuitBreaker.getState().equals(CircuitBreaker.State.CLOSED)){
            circuitBreaker.transitionToClosedState();
        }
    }
}

Реф. Проект: https://github.com/resilience4j/resilience4j-spring-boot2-demo

Предложенный Soln Обсуждение: https://github.com/resilience4j/resilience4j-spring-boot2-demo/issues/33

Предлагаемый Soln проект: https://github.com/shah-smit/resilience4j-spring-boot2-demo-maven

Ответы [ 2 ]

1 голос
/ 09 марта 2020

Похоже, что CircuitBreakerRegistry, который вы пытаетесь использовать в своем тесте для автоматического подключения, является фабричным классом, а не бином. Вместо @Autowired protected CircuitBreakerRegistry registry;
Попробуйте: protected CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults()

0 голосов
/ 10 марта 2020

Вот ответ о неработающих тестах.
Несколько вещей здесь:
1. Использование CircuitBreakerRegistry.ofDefaults() каждый раз создает новый экземпляр объекта, так что CircuitBreakerRegistry объекты, которые вы используете в AbstractCircuitBreakerTest и HomeService - это разные экземпляры. Вероятно, вам следует go вернуться к @Autowired аннотации, но сначала вам нужно определить bean-компонент CircuitBreakerRegistry следующим образом:

public class CircuitBreakerConfiguration {

    @Bean
    public CircuitBreakerRegistry circuitBreakerRegistry() {
        return CircuitBreakerRegistry.ofDefaults();
    }
}
Вы используете @RunWith(SpringRunner.class), но это просто аннотация Junit, и она не инициализирует Spring Context в вашем тесте. Вы автоматически подключаете bean-компонент в своем тесте, поэтому вам нужен Spring Context. Для этого добавьте также аннотацию @SpringBootTest. Вы ожидаете, что состояние реестра BACKEND_A изменится на OPEN после 11 вызовов метода service.getGreeting(), но я не вижу возможности использования метода transitionToOpenState .
...