Hystrix fallbackMethod will not be called in unit test? - unit-testing

I am starting to use Hystrix on my application to deal with data coming from external services. Some main points in my code:
#HystrixCommand(fallbackMethod = "getImagesFallback")
public ImageResultResource getImages(String url)
{
ResponseEntity<ResultResource> result = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(getRequestHeaders()), ResultResource.class);
return result.getBody().getImageResultResource();
}
public ImageResultResource getImagesFallback(String url, Throwable e)
{
return new ImageResultResource();
}
In my unit test, I would like to test the fallback case, for example when the external service returns 404 Not Found response, so I mock my test like below:
doThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND))//
.when(Mockito.spy(new ImageConnector()))//
.getImages(myMockedURL)
But when I run the test, it seems that the fallbackMethod that I defined above was not called. It returned directly the 404 Not Found that I mocked for the external service while I expect that the fallbackMethod should be catched here and no 404 Not Found will be thrown here.
Can anyone give me hint how can I test my fallbackMethod in this case, or did I make something wrong with the configuration here? Thank you so much!

Your fallback method needs to have the same signature as the method with the HystrixCommand annotation or the same signature with the addition of a Throwable. Here is the relevant Javanica documentation
public ImageResultResource getImagesFallback(String url, Throwable e) {
return new ImageResultResource();
}

Hystrix custom fallback methods throws the exception having the instance of HystrixRuntimeException..
So, you need to catch this exception and use getMessage method of it to print it.

Related

Unit Test expects System.ServiceModel.FaultException

This is my Unit Test:
[TestCategory("Repo")]
[TestMethod]
[ExpectedException(typeof(System.ServiceModel.FaultException))]
public void RepoUnitTest_ExpectError()
{
var repo = new CreateClientRepository(ClientServiceWrapper);
IClientObject input = new ClientObject
{
ClientId = 0,
ClientName = null
};
repo.CreateClient(input);
}
I am providing invalid input to my client repository which in turn calls a third party client service, and I expect the client service to throw an error. And, client service throws an exception too, but not the way I expect it. I expect it "System.ServiceModel.FaultException", but it give me this:
Test method RepoUnitTest_ExpectError threw exception
System.ServiceModel.FaultException`1[[System.ServiceModel.ExceptionDetail, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],
but exception System.ServiceModel.FaultException was expected.
Not sure what do I put in "ExpectedException" so this Unit Test passes with correctly expected exception.
Guess I should have waited few more minutes before posting this question, but I am glad did, now I can share the knowledge with whoever stumbles upon similar issue.
The expected exception should be written this way (for this particular case):
[ExpectedException(typeof(System.ServiceModel.FaultException<
System.ServiceModel.ExceptionDetail>))]

Resttemplate unit testing

I am trying to unit test a method which is calling a resttemplate inside. But somehow my test is not working. The method that I want to test looks so
public Integer createAccount(Request request) {
final String uri = "http://localhost:8080/stubs/otl/account/create";
return restTemplate.postForObject(uri, request, Integer.class);
}
My Unit tests looks so
#InjectMocks
AccountServiceImpl accountService;
#Mock
RestTemplate restTemplate;
#Value("${url.otl}")
private String urlOtl = "http://localhost:8080/stubs/otl/";
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
#Test
public void createAccountTest(){
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo(urlOtl+"account/create"))
.andExpect(method(HttpMethod.POST))
.andRespond(withSuccess("1", MediaType.APPLICATION_JSON));
Request request = new Request();
Integer result = accountService.createAccount(request);
mockServer.verify();
Assert.assertEquals("1", String.valueOf(result));
}
When I ran the test, I get as response
java.lang.AssertionError: Further request(s) expected 0 out of 1 were
executed at
org.springframework.test.web.client.MockRestServiceServer.verify(MockRestServiceServer.java:167)
Can somebody tell me what I am missing or doing wrong.
A MockRestServiceServer has a list of expectedRequests within it, that represent requests to the server that have been set up and are expected to be called.
verify() then asserts that all these expected requests have been called and hit the server.
So it seems like in your case, the "http://localhost:8080/stubs/otl/account/create" request is expected, but hasn't been called before the verify() method has been called, so verify() fails its assertion.
I faced the same issue. The Reason for the above error is either the rest url is not getting hit or the result is not coming as expected.
Ran into this issue recently and took me ages to figure out. I was not hitting my endpoint and you are probably doing the same. The issue is probably set up related. Maybe restTemplate hasnt been set up correctly in the test or service. Do a null check for resttemplate somewhere

Service #Transactional exception translation

I have a web service with an operation that looks like
public Result checkout(String id) throws LockException;
implemented as:
#Transactional
public Result checkout(String id) throws LockException {
someDao.acquireLock(id); // ConstraintViolationException might be thrown on commit
Data data = otherDao.find(id);
return convert(data);
}
My problem is that locking can only fail on transaction commit which occurs outside of my service method so I have no opportunity to translate the ConstraintViolationException to my custom LockException.
Option 1
One option that's been suggested is to make the service delegate to another method that's #Transactional. E.g.
public Result checkout(String id) throws LockException {
try {
return someInternalService.checkout(id);
}
catch (ConstraintViolationException ex) {
throw new LockException();
}
}
...
public class SomeInternalService {
#Transactional
public Result checkout(String id) {
someDao.acquireLock(id);
Data data = otherDao.find(id);
return convert(data);
}
}
My issues with this are:
There is no reasonable name for the internal service that isn't already in use by the external service since they are essentially doing the same thing. This seems like an indicator of bad design.
If I want to reuse someInternalService.checkout in another place, the contract for that is wrong because whatever uses it can get a ConstraintViolationException.
Option 2
I thought of maybe using AOP to put advice around the service that translates the exception. This seems wrong to me though because checkout needs to declare that it throws LockException for clients to use it, but the actual service will never throw this and it will instead be thrown by the advice. There's nothing to prevent someone in the future from removing throws LockException from the interface because it appear to be incorrect.
Also, this way is harder to test. I can't write a JUnit test that verifies an exception is thrown without creating a spring context and using AOP during the tests.
Option 3
Use manual transaction management in checkout? I don't really like this because everything else in the application is using the declarative style.
Does anyone know the correct way to handle this situation?
There's no one correct way.
A couple more options for you:
Make the DAO transactional - that's not great, but can work
Create a wrapping service - called Facade - whose job it is to do exception handling/wrapping around the transactional services you've mentioned - this is a clear separation of concerns and can share method names with the real lower-level service

Mockito gives UnfinishedVerificationException when it seems OK

Mockito appears to be throwing an UnfinishedVerificationException when I think I've done everything correctly. Here's my partial test case:
HttpServletRequest req = mock(HttpServletRequest.class);
when(req.getHeader("Authorization")).thenReturn("foo");
HttpServletResponse res = mock(HttpServletResponse.class);
classUnderTest.doMethod(req, res); // Use the mock
verify(res, never());
verify(req).setAttribute(anyString(), anyObject());
And here's the partial class and method:
class ClassUnderTest extends AnotherClass {
#Override
public String doMethod(ServletRequest req, ServletRequest res) {
// etc.
return "someString";
}
}
Ignoring the fact that you should never mock interfaces you don't own, why is Mockito giving me the following message?
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at (redacted)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
at [test method name and class redacted]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
... etc
This might also be caused if you try to verify a method which expects primitive arguments with any():
For example, if our method has this signature:
method(long l, String s);
And you try to verify it like this, it will fail with aforementioned message:
verify(service).method(any(), anyString());
Change it to anyLong() and it will work:
verify(service).method(anyLong(), anyString());
I just came across this my self and it caused me a lot of confusion.
As David mentioned above Mockito reports errors in the next Mockito method call which may not be in the same test method. While the exception message does contain a reference to the actual place the error occurred I find having incorrect tests failing counter productive to the testing process. And the simpler the tests the more likely an error is to show up in the next test!
Here is an easy fix that will ensure errors appear in the correct test method:
#After
public void validate() {
validateMockitoUsage();
}
From the Mockito documentation here:
Mockito throws exceptions if you misuse it so that you know if your
tests are written correctly. The gotcha is that Mockito does the
validation next time you use the framework (e.g. next time you verify,
stub, call mock etc.). But even though the exception might be thrown
in the next test, the exception message contains a navigable stack
trace element with location of the defect. Hence you can click and
find the place where Mockito was misused.
Sometimes though, you might
want to validate the framework usage explicitly. For example, one of
the users wanted to put validateMockitoUsage() in his #After method so
that he knows immediately when he misused Mockito. Without it, he
would have known about it not sooner than next time he used the
framework. One more benefit of having validateMockitoUsage() in #After
is that jUnit runner will always fail in the test method with defect
whereas ordinary 'next-time' validation might fail the next test
method. But even though JUnit might report next test as red, don't
worry about it and just click at navigable stack trace element in the
exception message to instantly locate the place where you misused
mockito.
I was getting this same error due to using any() with a boolean parameter, when apparently it needed to be anyBoolean().
In my case, using kotlin was because the funcion to test was not declared as open.
The exception notices that no final/private/equals/hash methods can be used.
fun increment(){
i++
}
to
open fun increment(){
i++
}
With Junit 5, you can add the following to show more meaningful Mockito exceptions in the console
#AfterEach
public void validate() {
validateMockitoUsage()
}
Also see this answer: https://stackoverflow.com/a/22550055/8073652
I had similar exception with class MyRepository
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at MyRepository$$FastClassBySpringCGLIB$$de8d8358.invoke()
Example of correct verification:
verify(mock).doSomething()
The problem was resolved when I created interface for MyRepository, and mock interface, but not implementation.
It seems spring creates some CGLIB proxies and it leads to UnfinishedVerificationException exception.
For me the issue turned out to be a missing bean declaration in the test context xml. It was for a custom aspect class used by another class, an instance of which is a parameter to the constructor of the class which is the parameter to failing verify() call. So I added the bean declaration to the context xml and it worked fine after that.
Changed to #RunWith(PowerMockRunner.class) and the issue went away.
Was using #RunWith(MockitoJUnitRunner.class) earlier.
Hope that helps someone..
I had the same issue, too, on the following stack:
Kotlin
Junit 4.13
Mockito 2.28.2 + Mockito-Inline 2.13.0
Robolectric 4.3.1
I tried to verify a lambda call:
#RunWith(RobolectricTestRunner::class)
class MainViewTest {
#get:Rule
val mockitoRule: MockitoRule = MockitoJUnit.rule()
#Mock private lateinit var mockClickCallback: () -> Unit
#Test
fun `should call clickCallback on the button click`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
val viewUnderTest = MainView(activity)
viewUnderTest.setClickCallback(mockClickCallback)
viewUnderTest.button.performClick()
verify(mockClickCallback).invoke() // UnfinishedVerificationException
}
}
Then I found the issue on Github, it seems that the problem is in Robolectric. I used the following workaround:
#RunWith(RobolectricTestRunner::class)
class MainViewTest {
private interface UnitFunction: () -> Unit
#Test
fun `should call clickCallback on the button click`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
val viewUnderTest = MainView(activity)
val mockClickCallback = mock(UnitFunction::class.java) as () -> Unit
viewUnderTest.setClickCallback(mockClickCallback)
viewUnderTest.button.performClick()
verify(mockClickCallback).invoke() // OK
}
}
Two answers above suggested using validateMockitoUsage() method after each test.
While this is correct I found that annotating your class with #ExtendWith(MockitoExtension.class)
in Junit 5 give the same effect while adding some the nice Mockito functionalities. Also, it looks cleaner to me as well.
I guess Junit 4 #RunWith(MockitoJUnitRunner.class) will give a similar result but I didn't test it.
I had a similar problem, i found a way to solve this. Mock objects which you for verify haven't been reseted, so you should reset it .You can reset(mock) before your test case function, it may be helpful.
If you try to verify a private or package-private method with Mockito.verify you will get this error.
If you don't want to use PowerMockito you can set your method as protected and I advise you to add the #VisibleForTesting tag:
Before:
void doSomething() {
//Some behaviour
}
After :
#VisibleForTesting
protected void doSomething() {
//Some behaviour
}
I was having the same error
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-at com.xxx.MyTest.testRun_Should_xxx_When_yyy(MyTest.java:127)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
at com.xxx.MyTest.validate(MyTest.java:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.MethodRoadie.runAfters(MethodRoadie.java:145)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:99)
...
In my case, the error was generated because I was using a PowerMockito.verifyStatic() before my Mockito.verify(...) call, then I had to move the PowerMockito.verifyStatic() to last line (or delete it).
From:
PowerMockito.verifyStatic();
Mockito.verify(myMock, Mockito.times(1)).myMockedMethod(anyString(), anyString(), anyString(), any(XXX.class), any(YYY.class), any(ZZZ.class));
To:
Mockito.verify(myMock, Mockito.times(1)).myMockedMethod(anyString(), anyString(), anyString(), any(XXX.class), any(YYY.class), any(ZZZ.class));
PowerMockito.verifyStatic();
Here is my grain of salt!
I discovered there is a conflict between Mockito and Hibernate Validation.
My solution is the separate my contract checks (#NotNull, #NotEmpty, etc) from the mockito tests. I also started using validateMockitoUsage() to ensure everything was run correctly.
The tests run individually well but while running integration test suite it fails with the UnfinishedVerificationException. The issue arises when we use verify() from mockito and have #EnableRetry.
Workaround for this is to use
public static <T> T unwrapAndVerify(T mock, VerificationMode mode) {
return ((T) Mockito.verify(AopTestUtils.getTargetObject(mock), mode));
}
as mentioned in Mocked Spring #Service that has #Retryable annotations on methods fails with UnfinishedVerificationException
I'm not sure where are your "classUnderTest" come from, but please keep sure it's mocked, not a real one.
I have the same issue for my test case below:
MyAgent rpc = new MyAgent("myNodeName");
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);
But it's disappeared for the following test case:
MyAgent rpc = PowerMockito.spy(new MyAgent("myNodeName"));
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);
Attention, the Object rpc should be mocked by PowerMockito.spy(...).
Faced same exception when used mockStatic method and called Mockito.verify multiple times, but passed interface instead of implementing class.
wrong code:
try (MockedStatic<Service> staticMock = Mockito.mockStatic(Service.class, Mockito.CALLS_REAL_METHODS)) {
staticMock.verify(() -> ServiceImpl.method()); // passed without errors
staticMock.verify(() -> ServiceImpl.method()); // throws UnfinishedVerificationException
}
fixed code:
try (MockedStatic<ServiceImpl> staticMock = Mockito.mockStatic(Service.class, Mockito.CALLS_REAL_METHODS)) {
staticMock.verify(() -> ServiceImpl.method());
staticMock.verify(() -> ServiceImpl.method());
}
It was my mistake obviosly, but UnfinishedVerificationException message was not helpfull

Grails testing a failing domain save in service

I've a Grails (3+) service where a domain object is retrieved from the DB, modified , and then updated in the DB.
class MyService {
def modifyObject(String uuid) {
def md = MyDomain.findByUuid(uuid)
md.someField = true
if (!md.save()){
throw new MyException()
}
}
}
Now I need to test this service method with a negative test, to be sure that the exception is thrown. But I can't figure out how to force a failing save in the service method.
#TestFor(MyService)
#Mock(MyDomain)
class MyServiceSpec extends Specification {
void "test An exceptionl situation was found"() {
given: "An uuid"
def md = new MyDomain(uuid: "123")
md.save(failOnError: true)
when: "service is called"
service.modifyObject("123")
then: "An exception is thrown"
thrown MyException
}
}
Obviously, re-defining the service method in a more functional way (the object is passed directly to the method, modified and returned without save .e.g MyDomain modifyObject(MyDomain md)) will be a good solution since I could create an invalid ad hoc object outside or even invalidate it after the method execution.
But the question is: "is there a way to test the service code as is?"
Assuming that you really do want to throw an exception and not just handle validation errors, then sure. You'll want to utilize Spock's support for interaction based testing and leverage static method stubs. See similar question, Unit test grails with domain objects using GORM functions.
You need some way to isolate the service method and stub out the GORM functionality. This can be tricky with static methods, but can be accomplished with a global GroovyMock or GroovySpy. In essence, you're replacing all instances/references to MyDomain for the duration of the method (though the GroovySpy will fall back on the actual domain class unless an interaction matches).
With the Mock/Spy in place, you can specify the interactions you expect to occur and specify what those interactions should return. In this case, we expect the findByUuid to be invoked with an argument of "123" once, and we return a mock MyDomain object. That mock object then has it's save() method invoked once where we return null, i.e. the save failed.
void "test An exceptional situation was found"() {
setup:
GroovySpy(MyDomain, global: true)
def mockDomain = Mock(MyDomain)
when: "service is called"
service.modifyObject("123")
then: "An exception is thrown"
1 * MyDomain.findByUuid("123") >> mockDomain
1 * mockDomain.save() >> null
thrown Exception
}
If you violate a constraint on MyDomain and the save should fail, no?
If the modifyObject is really that simple, and you can't pass in a bogus value to force a constraint violation, maybe you need to metaClass the MyDomain.save and force a failure there.