【问题标题】:Unresolved dependency in UnitTesting Spring BootUnitTesting Spring Boot 中未解决的依赖关系
【发布时间】:2020-06-21 11:16:54
【问题描述】:

尝试为 CircuitBreaker 代码示例编写单元测试时出现以下错误。

org.springframework.beans.factory.UnsatisfiedDependencyException: 创建具有名称的 bean 时出错 'com.foosball.team.Service.TeamServiceUnitTest':不满意 通过字段“注册表”表示的依赖关系;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 符合条件的 bean 类型 'io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry' 可用:预计至少有 1 个符合 autowire 条件的 bean 候选人。依赖注解: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

团队服务:

@Service
public class TeamService {

    @Autowired
    private ITeamRepository teamRepository;

    @Autowired
    private PlayerClient playerClient;

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

团队服务单元测试:

@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

【问题讨论】:

  • 嗨@Smit,你成功完成了测试吗?我有代码编译但测试失败的问题,因为断路器没有打开。
  • 嗨@PauloWeverton,您能否确保您的计算机有足够的资源来打开断路器。当我在 Jenkins 中运行构建时,测试通过就好了,但有时在我的计算机上它不起作用。
  • 我愿意。当运行应用程序并使用测试系统使用它时,一切都很顺利,CircuitBreaker 和 FeignClient 等。但是 junit 测试没有:(

标签: java spring spring-boot resilience4j


【解决方案1】:

看起来您尝试在测试中自动装配的 CircuitBreakerRegistry 是工厂类,而不是 bean。代替 @Autowired protected CircuitBreakerRegistry registry;
尝试: protected CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults()

【讨论】:

  • 谢谢。这解决了这个问题。我可以知道,为什么测试失败了?
  • 您没有提供 TeamService 方法的实现,所以我无法告诉您原因。另外我不知道它失败的错误消息是什么......也许尝试一些调试。
  • 我在这里上传了失败的项目:github.com/shah-smit/Resilience4j-Spring-Boot-demo也许你可以帮我解决它。
【解决方案2】:

这是关于无法正常工作的测试的答案。
这里有几件事:
1. 使用CircuitBreakerRegistry.ofDefaults() 每次都会创建新的对象实例,因此您在AbstractCircuitBreakerTestHomeService 中使用的CircuitBreakerRegistry 对象是不同的实例。您可能应该回到@Autowired 注释,但首先您需要像这样定义CircuitBreakerRegistry 的bean:

public class CircuitBreakerConfiguration {

    @Bean
    public CircuitBreakerRegistry circuitBreakerRegistry() {
        return CircuitBreakerRegistry.ofDefaults();
    }
}
  1. 您使用的是@RunWith(SpringRunner.class),但它只是Junit 注释,它不会在您的测试中初始化Spring Context。您正在测试中自动装配一个 bean,因此您需要 Spring Context。为此还要添加 @SpringBootTest 注释。
  2. 您预计注册表 BACKEND_A 状态会在 11 次调用 service.getGreeting() 方法后更改为 OPEN,但我看不到 transitionToOpenState 方法的任何用法。

【讨论】:

猜你喜欢
  • 2018-03-11
  • 2013-02-11
  • 2017-10-11
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 2016-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多