UnitTesting Spring 引导中未解决的依赖关系
Unresolved dependency in UnitTesting Spring Boot
我在尝试为 CircuitBreaker 代码示例编写单元测试时遇到以下错误。
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.foosball.team.Service.TeamServiceUnitTest': Unsatisfied
dependency expressed through field 'registry'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{@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);
}
}
参考 Class:
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
看起来您在测试中尝试自动装配的 CircuitBreakerRegistry 是一个工厂 class,而不是一个 bean。代替
@Autowired
protected CircuitBreakerRegistry registry;
尝试:
protected CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults()
这里是关于不工作测试的回答。
这里有一些东西:
1. 使用 CircuitBreakerRegistry.ofDefaults()
每次都会创建对象的新实例,因此您在 AbstractCircuitBreakerTest
和 HomeService
中使用的 CircuitBreakerRegistry
对象是不同的实例。您可能应该回到 @Autowired
注释,但首先您需要像这样定义 CircuitBreakerRegistry
的 bean:
public class CircuitBreakerConfiguration {
@Bean
public CircuitBreakerRegistry circuitBreakerRegistry() {
return CircuitBreakerRegistry.ofDefaults();
}
}
- 您正在使用
@RunWith(SpringRunner.class)
但它只是 Junit 注释,它不会在您的测试中初始化 Spring 上下文。您正在测试中自动装配一个 bean,因此您需要 Spring 上下文。为此还添加 @SpringBootTest
注释。
- 您希望注册表
BACKEND_A
状态在调用 service.getGreeting()
方法 11 次后更改为 OPEN
,但我看不到 transitionToOpenState
方法的任何用法。
我在尝试为 CircuitBreaker 代码示例编写单元测试时遇到以下错误。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.foosball.team.Service.TeamServiceUnitTest': Unsatisfied dependency expressed through field 'registry'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@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);
}
}
参考 Class:
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
看起来您在测试中尝试自动装配的 CircuitBreakerRegistry 是一个工厂 class,而不是一个 bean。代替
@Autowired
protected CircuitBreakerRegistry registry;
尝试:
protected CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults()
这里是关于不工作测试的回答。
这里有一些东西:
1. 使用 CircuitBreakerRegistry.ofDefaults()
每次都会创建对象的新实例,因此您在 AbstractCircuitBreakerTest
和 HomeService
中使用的 CircuitBreakerRegistry
对象是不同的实例。您可能应该回到 @Autowired
注释,但首先您需要像这样定义 CircuitBreakerRegistry
的 bean:
public class CircuitBreakerConfiguration {
@Bean
public CircuitBreakerRegistry circuitBreakerRegistry() {
return CircuitBreakerRegistry.ofDefaults();
}
}
- 您正在使用
@RunWith(SpringRunner.class)
但它只是 Junit 注释,它不会在您的测试中初始化 Spring 上下文。您正在测试中自动装配一个 bean,因此您需要 Spring 上下文。为此还添加@SpringBootTest
注释。 - 您希望注册表
BACKEND_A
状态在调用service.getGreeting()
方法 11 次后更改为OPEN
,但我看不到transitionToOpenState
方法的任何用法。