I have this catch statement:
catch (NotFoundException ex) {
ex.getError().setTitle(NOT_FOUND);
throw new NotFoundException(resource, id, ex.getError());
}
How can I mock this exception? I've tried this
when(service
.filter(eq(any()), eq(any()), eq(any())))
.thenThrow(new NotFoundException(anyString(), anyString()));`
But it gives me a null exception error because of this line:
ex.getError().setTitle(NOT_FOUND);
The constructor is:
public NotFoundException(String resource, String id, Error error) {
this.resource = resource;
this.ids = Collections.singletonList(id);
this.error = error;
}
And I can't get the exception variable to set the title, or find an way to mock it.
Thanks for you help!
.thenThrow(new NotFoundException(anyString(), anyString()));
This isn't allowed: anyString() only stands directly in for the call in when and verify. In your call to filter, simply use any() rather than eq(any()), but you're otherwise using matchers in the correct place.
Furthermore, it looks like your system-under-test assumes that ex.getError() is non-null; it is likely that you'll need to pass in a useful Error instance as constructor parameter into the NotFoundException you create.
.thenThrow(new NotFoundException("foo", "bar", new Error(/* ... */)))
Naturally, if your Error is difficult to create or work with, you might use a mock(Error.class) instead.
Related
In my request handler, if the passed-in accountId cannot be converted to a valid ObjectId I want to catch the error and send back a meaningful message; however, doing so causes the return type to be incompatible, and I cannot figure out how to achieve this pretty trivial use case.
My code:
#GetMapping("/{accountId}")
public Mono<ResponseEntity<Account>> get(#PathVariable String accountId) {
log.debug(GETTING_DATA_FOR_ACCOUNT, accountId);
try {
ObjectId id = new ObjectId(accountId);
return repository.findById(id)
.map(ResponseEntity::ok)
.switchIfEmpty(Mono.just(ResponseEntity.notFound().build()));
} catch (IllegalArgumentException ex) {
log.error(MALFORMED_OBJECT_ID, accountId);
// TODO(marco): find a way to return the custom error message. This seems to be currently
// impossible with the Reactive API, as using body(message) changes the return type to
// be incompatible (and Mono<ResponseEntity<?>> does not seem to cut it).
return Mono.just(ResponseEntity.badRequest().build());
}
}
The body(T body) method changes the type of the returned Mono so that it is (assuming one just sends a String) a Mono<ResponseEntity<String>>; however, changing the method's return type to Mono<ResponseEntity<?>> does not work either:
...
return Mono.just(ResponseEntity.badRequest().body(
MALFORMED_OBJECT_ID.replace("{}", accountId)));
as it gives an "incompatible type" error on the other return statement:
error: incompatible types: Mono<ResponseEntity<Account>> cannot be converted to Mono<ResponseEntity<?>>
.switchIfEmpty(Mono.just(ResponseEntity.notFound().build()));
Obviously, changing the return type of the method to Mono<?> would work, but the response then is the serialized JSON of the ResponseEntity which is NOT what I want.
I have also tried using the onErrorXxxx() methods, but they do not work here either, as the conversion error happens even before the Flux is computed, and I just get a "vanilla" 400 error with an empty message.
The only way I can think of working around this would be to add a message field to my Account object and return that one, but it's genuinely a horrible hack.
#thomas-andolf's answer helped me figure out the actual solution.
For anyone stumbling upon this in future, here is how I actually solved the puzzle (and, yes, you still need the try/catch to intercept the error thrown by the ObjectId constructor):
#GetMapping("/{accountId}")
public Mono<ResponseEntity<Account>> get(#PathVariable String accountId) {
return Mono.just(accountId)
.map(acctId -> {
try {
return new ObjectId(accountId);
} catch (IllegalArgumentException ex) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
MALFORMED_OBJECT_ID));
}
})
.flatMap(repository::findById)
.map(ResponseEntity::ok)
.switchIfEmpty(Mono.just(ResponseEntity.notFound().build()));
}
To actually see the message in the returned body, you will need to add server.error.include-message=always in application.properties (see here).
Using onError() won't work here (I did try that, in all its variants) as it requires a Mono<ResponseEntity<Account>> and there is no way to generate one from the error status (when adding the message body).
I'm trying to get the same result as when I use #Valid in object parameter from a Controller. When the object is invalid an exception (MethodArgumentNotValidException) is throw by my ExceptionHandlerController who has #RestControllerAdvice.
In my case I want to validate an object, but I only can validate it in service layer. The object have bean validation annotations, so I'm trying to programmatically throw MethodArgumentNotValidException for my ExceptionHandlerController handle it, but I'm not having success.
So far I have this:
private void verifyCard(CardRequest card) {
BeanPropertyBindingResult result = new BeanPropertyBindingResult(card, "card");
SpringValidatorAdapter adapter = new SpringValidatorAdapter(this.validator);
adapter.validate(card, result);
if (result.hasErrors()) {
try {
throw new MethodArgumentNotValidException(null, result);
} catch (MethodArgumentNotValidException e) {
e.printStackTrace();
}
}
}
The first parameter is from type MethodParameter and I'm not been able to create this object. Is it the best way to handle my problem?
EDIT 1:
I can't remove the try/catch block. When I remove it I get compile error. How to work around?
You have already handled it by the catch block, you should remove try-catch to your global handler catch it.
then specify the method like below
private void verifyCard(CardRequest card) throws MethodArgumentNotValidException
MethodArgumentNotValidException is a subclass of Exception. This means that it's "checked": To throw it out of your verifyCard(..) method, you have to declare that verifyCard(..) can throw it:
private void verifyCard(CardRequest card) throws MethodArgumentNotValidException {
// your code
}
If you have lombok dependency in your project, you can also fake compiler by using #SneakyThrows annotation.
https://projectlombok.org/features/SneakyThrows
throw new MethodArgumentNotValidException(null, result);
Above constructor will not work as method parameter is necessary.
Valid constructor (reference) is:
MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult);
Hence, in your case:
throw new MethodArgumentNotValidException(new MethodParameter(
this.getClass().getDeclaredMethod("verifyCard", YourClassName.class), 0), errors);
I have actual method below:
public ResponseEntity<Message> catEnter(#PathVariable("catId") BigInteger catId, #RequestBody Catrequest catReq, HttpServletRequest request) throws CatDataException, InvalidCatExcecatption {
Message message = new Message();
try {
message = catManager.submitData(catReq.getMessage(), catId, request);
} catch (IOException e) {
throw new CatDataAppException(e.getMessage());
}
return (ResponseEntity<Message>) restResponse(message, request.getMethod());
// Getting null pointer exception in above line
}
I am using mockito for my test code as below:
#Test
public void submitData() throws Exception {
Message mes = new Message();
mes.setCode("00");
mes.setMessage("hi");
ResponseEntity<Message> responseentity = ((ResponseEntity<Message>) catController.catEnter(BigInteger.valueOf(3431), catRequest, mockRequest));
}
I'm getting null pointer exception, Message going as a null, even I set the value explicitly?
Here:
You pass mockRequest when making that call to your production code:
ResponseEntity<Message> responseentity = ... catController.catEnter(... mockRequest));
And your production call does:
return (ResponseEntity<Message>) restResponse(message, request.getMethod());
So the only conclussion: mockRequest is null!
So, first make sure that the passed variable is not null; like:
Request mockedRequest = mock(Request.class);
Or, use the #Mock annotation in case that mockedRequest is a field in your test class.
On top of that; you probably want to do some mock-specification, like:
when(mockedRequest.getMethod()).thenReturn( whatever )
But beyond that, you are lacking a lot of the fundamental basics of Java:
naming conventions: variable names go camelCase, like entityResponse. And typically, tests are named like testCatEnter to express the method that is tested.
You have casts ... where they are not required.
You have quite some code there ... that is unused, like the mes declaration in your test method.
Long story short: I have the feeling that you are overburdening yourself dramatically. First learn the basics; then go for the advanced Mockito stuff.
I have a situation where I want to mock a web service call. The approach I am using is if the service is down, it throws an exception. I intent to use that exception using ThrowAdvice AOP in spring and want to suppress the exception and replace the response object with my dummy object. How can I do so?
I suggest you to use Around advice to intercept the method. This advice will give you absolute control. In this advice you can catch the exception and return the require response
#Around("execution(abc.example.*Service.*(..))")
public ResultType execute(ProceedingJoinPoint p) {
ResultType result = null;
try {
result = (ResultType) p.proceed();
return result;
} catch (Throwable t) {}
// Create dummy result
return result;
}
ResultType can be any type, but be sure not intercept service which are not returning same type or subtype
with the following code I get NP_NULL_PARAM_DEREF: Method call passes null for nonnull parameter:
public void calledAnywhereIDoNotCare() {
//[...]
//parameter could be null but shouldn't ever be by logic
method(parameter); //FindBugs says the problem is here
//[...]
}
public final ReturnType method(final ParameterType parameter) {
//this method do nothing but simply call anotherMethod()
return anotherMethod(parameter, false);
}
public final ReturnType anotherMethod(final ParameterType parameter, boolean boolParam) {
if (parameter == null) {
//just in case logic is wrong
throw new NullPointerException("I know it shouldn't be null by logic, but it is null!");
}
//do something very usefull
//[...]
}
So, my question is: Why did I get this NP_NULL_PARAM_DEREF and what changes would be better?
Did I get this because of declaring the parameter final? Or because of not catching the NullPointerException? I don't want to catch it, it should be catched somewhere out there. Maybe I should declare throwing NullPointerException in calledAnywhereIDoNotCare()?
Thank you for your help.
TARL
In your comment you write that the parameter "could" be null but never will because of the program logic. FindBugs doesn't know/understand the logic. The best way would be to let FindBugs ignore the NP_NULL_PARAM_DEREF in this method using the edu.umd.cs.findbugs.annotations.SuppressWarnings annotation. See http://findbugs.sourceforge.net/manual/annotations.html