How can I unit-test javanica @HystrixCommand annotated methods?
Although you shouldn't necessarily UNIT test hystrix command. It's still useful to have a sort of spring hybrid test, I think point blank accepting the functionality when adding the annotation isn't correct. The test I created ensures that the circuit breaker opens on an exception.
@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);
}
}
Another little thing that tripped me up for a while was that I had entered the default annotations without a specific command key, however when the command keys are created they are created against the method name which is what I've specified above. For a complete example I've also added the annotation to show I didn't specify a commandKey.
@HystrixCommand
public Optional<Document> findOneById(final String id) {
return this.myRepo.findOneById(id);
}
Hope this helps someone.
Hystrix is a tool that you accept is functional, much like Spring is a tool that you accept is functional. You do not need to unit test the ability of Hystrix to call your fallback method.
You should unit test the fallback method by calling it directly in a unit test.
That said, you are likely to want to test that Hystrix is actually calling the fallback method when you want Hystrix to call the fallback method; this will not be a unit test, it will be an integration test.
While it is possible to to write many integration tests using jUnit, it seems clear that Hystrix does not want to participate in jUnit tests.
I suggest that you should install your application in a development and/or qa test environment and test the Hystrix fallback functionality by forcing fallback on a running system.