我正在使用javanica并注释我的hystrix命令方法,如下所示:
@HystrixCommand(groupKey="MY_GROUP", commandKey="MY_COMMAND" fallbackMethod="fallbackMethod")
public Object getSomething(Object request) {
....
我正在尝试对我的回退方法进行单元测试,而不必直接调用它们,即我想调用@HystrixCommand
带注释的方法,并在抛出500错误后让它自然流入回退。这一切都在单元测试之外工作。
在我的单元测试中,我使用spring MockRestServiceServer
来返回500个错误,这部分正在运行,但Hystrix没有在我的单元测试中正确初始化。在我的测试方法开始时,我有:
HystrixRequestContext context = HystrixRequestContext.initializeContext();
myService.myHystrixCommandAnnotatedMethod();
在此之后我试图通过键获取任何hystrix命令并检查是否有任何已执行的命令但列表始终为空,我使用此方法:
public static HystrixInvokableInfo<?> getHystrixCommandByKey(String key) {
HystrixInvokableInfo<?> hystrixCommand = null;
System.out.println("Current request is " + HystrixRequestLog.getCurrentRequest());
Collection<HystrixInvokableInfo<?>> executedCommands = HystrixRequestLog.getCurrentRequest()
.getAllExecutedCommands();
for (HystrixInvokableInfo<?> command : executedCommands) {
System.out.println("executed command is " + command.getCommandGroup().name());
if (command.getCommandKey().name().equals(key)) {
hystrixCommand = command;
break;
}
}
return hystrixCommand;
}
我意识到我在单元测试初始化中遗漏了一些东西,有人能指出我如何正确地对其进行单元测试吗?
答案 0 :(得分:6)
Hystrix是您接受的功能, 很像Spring是一个你接受的功能。 您不需要对Hystrix调用您的后备方法的能力进行单元测试。
您应该通过在单元测试中直接调用它来对回退方法进行单元测试。
那说, 当你希望Hystrix调用回退方法时,你可能想要测试Hystrix实际上正在调用回退方法; 这不是单元测试, 这将是一次整合测试。
虽然可以使用jUnit编写许多集成测试, 很明显,Hystrix不想参加jUnit测试。
我建议您应该在开发和/或qa测试环境中安装应用程序,并通过强制在正在运行的系统上进行回退来测试Hystrix回退功能。
答案 1 :(得分:6)
虽然你不一定要UNIT测试hystrix命令。进行一种弹簧混合测试仍然很有用,我认为在添加注释时接受功能的空白是不正确的。我创建的测试确保断路器在例外情况下打开。
@RunWith(SpringRunner.class)
@SpringBootTest
public class HystrixProxyServiceTests {
@MockBean
private MyRepo myRepo;
@Autowired
private MyService myService;
private static final String ID = “1”;
@Before
public void setup() {
resetHystrix();
openCircuitBreakerAfterOneFailingRequest();
}
@Test
public void circuitBreakerClosedOnSuccess() throws IOException, InterruptedException {
when(myRepo.findOneById(USER_ID1))
.thenReturn(Optional.of(Document.builder().build()));
myService.findOneById(USER_ID1);
HystrixCircuitBreaker circuitBreaker = getCircuitBreaker();
Assert.assertTrue(circuitBreaker.allowRequest());
verify(myRepo, times(1)).findOneById(
any(String.class));
}
@Test
public void circuitBreakerOpenOnException() throws IOException, InterruptedException {
when(myRepo.findOneById(ID))
.thenThrow(new RuntimeException());
try {
myService.findOneById(ID);
} catch (RuntimeException exception) {
waitUntilCircuitBreakerOpens();
HystrixCircuitBreaker circuitBreaker = getCircuitBreaker();
Assert.assertFalse(circuitBreaker.allowRequest());
}
verify(myRepo, times(1)).findOneById(
any(String.class));
}
private void waitUntilCircuitBreakerOpens() throws InterruptedException {
Thread.sleep(1000);
}
private void resetHystrix() {
Hystrix.reset();
}
private void warmUpCircuitBreaker() {
myService.findOneById(USER_ID1);
}
public static HystrixCircuitBreaker getCircuitBreaker() {
return HystrixCircuitBreaker.Factory.getInstance(getCommandKey());
}
private static HystrixCommandKey getCommandKey() {
return HystrixCommandKey.Factory.asKey("findOneById");
}
private void openCircuitBreakerAfterOneFailingRequest() {
ConfigurationManager.getConfigInstance().
setProperty("hystrix.command.findOneById.circuitBreaker.requestVolumeThreshold", 1);
}
}
让我感到困惑的另一件小事是我输入了没有特定命令键的默认注释,但是当创建命令键时,它们是根据我在上面指定的方法名称创建的。对于一个完整的例子,我还添加了注释,以表明我没有指定commandKey。
@HystrixCommand
public Optional<Document> findOneById(final String id) {
return this.myRepo.findOneById(id);
}
希望这有助于某人。
答案 2 :(得分:0)
我现在遇到了一个问题:如果包装方法的方法签名发生更改,则无需编译时或启动检查后备方法是否仍可调用。因此,如果将int arg更改为String,而我忘记更改fallback方法的签名,则直到应用程序运行并调用包装方法时,我才知道。
答案 3 :(得分:0)
可能为时已晚。 但是您可以使用该方法在代码运行之前实例化一个
我是这样做的
public void warmUpCircuitBreaker() {
HystrixCommandKey commandKey= HystrixCommandKey.Factory.asKey("test");
HystrixCommandProperties.Setter setter = HystrixCommandProperties.defaultSetter();
HystrixPropertiesCommandDefault hystrixPropertiesCommandDefault = new HystrixPropertiesCommandDefault(commandKey, setter);
HystrixCommandGroupKey test = HystrixCommandGroupKey.Factory.asKey("Test");
HystrixCircuitBreaker.Factory.getInstance(commandKey,
test,
hystrixPropertiesCommandDefault,
HystrixCommandMetrics.getInstance(commandKey, test, hystrixPropertiesCommandDefault));
}
在调用SUT之前调用此方法 您也可以设置所有必需的属性
在我的测试中 我正在设置属性以测试不同的场景
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.test.circuitBreaker.forceClosed",
true);