I have method in java class :
#Context
UriInfo uriInfo;
public void processRequest(#QueryParam ("userId") #DefaultValue("") String userId)
{
String baseURI = uriInfo.getBaseUri().toString();
if(userId == null)
{
//UserIdNotFoundException is my custom exception which extends Exceptition
throw new UserIdNotFoundException();
}
}
When I'm junit testing the above method expecting for UserIdNotFoundException when userId parameter is Null, I get the following Assertion error : expected an instance of UserIdNotFoundException but <java.lang.NullPointerException> is java.lang.NullPointerException.
#Test
public void testProcessRequest_throws_UserIdNotFoundException()
{
expectedException.expect(UserIdNotFoundException.class);
processRequest(null);
}
My custom exception class :
public class UserIdNotFoundException extends Exception
{
public UserIdNotFoundException()
{
}
public UserIdNotFoundException(String message)
{
super(message);
}
}
I prefer the annotation:
#Test(expected = UserIdNotFoundException.class)
public void testProcessRequest_throws_UserIdNotFoundException() {
processRequest(null);
}
The problem might be that your processRequest implementation might be hitting the NPE before you have a chance to check for user id.
This is a good thing: Your test shows that the implementation does not meet your requirement. You can fix it forever now.
This is what TDD is good for.
You have to write custom Exception class this example might help you.
sample code:
class UserIdNotFoundException extends Exception{
UserIdNotFoundException (String s){
super(s);
}
}
Test Exception:
public void processRequest(String userId)
{
if(userId == null)
{
//UserIdNotFoundException is my custom exception which extends Exception
throw new UserIdNotFoundException("SOME MESSAGE");
}
}
remove default constructor from your exception class, JVM implicitly create it for you/
You probably did not set uriInfo with a value and you're calling a method on a null value. Are you sure you're test is setup to give a value to uriInfo ? Or getBaseUri() might be returning null and calling toString() on it might throw the NullPointerException. This would be done by inspecting the return value of getBaseUri() in a debugger.
Normally you can either run your test with a config with beans for your test or you can add setter to set the value in your class of test to mock it or give a value in test. This should help avoid NullPointerException.
Either way you should always do the fail verification before doing any real work in a method.
Related
Trying to write a test that will call my method, when that method makes a call to another method we will throw a custom exception i have made. Here i have simplified it all
2 functions
public MyJsonResponse hello() {
MyJsonResponse response = new MyJsonResponse();
response.setErrorMessage("1");
response.setStatus("some status");
response.setData("1");
response.setHttpResponse(200);
try{
hi();
return response;
}catch (MyServiceException e) {
response.setErrorMessage(e.getMessage());
response.setStatus("error creating");
response.setData("2");
response.setHttpResponse(e.getResponseStatus());
return response;
}
}
public String hi() throws MyServiceException{
LOG.error("Exception");
return "yea";
}
The test I have written is this
#Test
public void myTest() throws Exception {
given(service.hi()).willAnswer( invocation -> { throw new MyServiceException("abc msg",511); });
MyJsonResponse actual = service.hello();
Assert.assertNotNull(actual);
assertEquals(511, actual.getHttpResponse());
}
But unfortunately the result is as follows
java.lang.AssertionError:
Expected :511
Actual :200
Please, be sure that you are using a spy as you want to use the actual code for some methods of your mocked service and just stubbing specific methods of it. Please, see for instance this related SO question about the subject.
Also, consider modifying your test definition to use willThrow instead of willAnswer: as pointed out by #eis, you can still use the later, but the former is more straightforward.
Your code will look similar to this:
#Test
public void myTest() throws Exception {
MyService service = spy(MyService.class);
willThrow(new MyServiceException("abc msg",511))
.given(service)
.hi()
;
// As pointed out by #eis, you can still use willAnswer
// willAnswer(
// invocation -> { throw new MyServiceException("abc msg",511);}
// )
// .given(service)
// .hi()
// ;
MyJsonResponse actual = service.hello();
Assert.assertNotNull(actual);
assertEquals(511, actual.getHttpResponse());
}
regarding what you explain and what your code look like, I am not sure if I have well understood.
Thus, if you want that, your hi() : function throws an exception.
You have to make it first throws an exception. Take a look at code below!
public String hi() throws MyServiceException{
/*LOG.error("Exception");//No don't just log, throw a real exception as below*/
throw new MyServiceException("text here, if your constructor support it or nothing otherwise")
/*return "yea";//Nothing to return? we have just break the code by throwing the exception above*/
}
After that, please be very sure that your 'MyServiceException.getHttpResponse()' will really return 511
For this test to make sense, your hi() call should be done calling another service that you stub/mock in your test class. You're not doing that, so this approach won't work.
You wrote "the real method that hi represents does a lot", so it's about time you extract that to another service.
May I ask what is the proper way to throw checked custom exception in Spring webflux please?
I would like to insist, it is about checked custom exception, like MyException.java, not something like RuntimeException, and it is about throwing exception, not handling exception.
I tried the following :
#Controller
#SpringBootApplication
public class QuestionHowToThrowException {
public static void main(String[] args) {
SpringApplication.run(QuestionHowToThrowException.class);
}
#PostMapping(path = "/question", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<ResponseEntity<QuestionResponse>> question(#RequestBody QuestionRequest questionRequest) {
Mono<FirstStep> firstStepMono = WebClient.create().post().uri("http://firstWebService:8111/getFirstStep")
.body(questionRequest.getThing(), String.class).retrieve().bodyToMono(FirstStep.class);
Mono<SecondStep> secondStepMono = firstStepMono.map(oneFirstStep -> getSecondStepFromFirstStepAfterCheck(oneFirstStep));
return secondStepMono.map(oneSecondStep -> ResponseEntity.ok(new QuestionResponse(oneSecondStep.getSecondThing())));
}
private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException {
if (firstStep.getThingNeedsToCheckCanThrowException().equals("exception")) {
throw new MyException("exception");
} else {
return new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good");
}
}
public class QuestionRequest {
private String thing;
public String getThing() {
return thing;
}
}
public class QuestionResponse {
private String response;
public QuestionResponse(String response) {
this.response = response;
}
}
public class FirstStep {
private String thingNeedsToCheckCanThrowException;
public String getThingNeedsToCheckCanThrowException() {
return thingNeedsToCheckCanThrowException;
}
}
public class SecondStep {
private String secondThing;
public SecondStep(String secondThing) {
this.secondThing = secondThing;
}
public String getSecondThing() {
return secondThing;
}
}
}
This is not possible, since there in an unhandled exception in getSecondStepFromFirstStepAfterCheck method.
If I throw and propagate, private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException the lambda caller method is not happy.
What is the cleanest and proper way to throw custom exception in webflux please?
Thank you
Reading through your sample code, it looks like you are trying to introduce some error handling with on your Mono.
You can create an unchecked exception by extending the RuntimeException class. If you want a checked exception that enforces handling, you can simply extend Exception.
public class MyException extends RuntimeException {
public MyException(String msg) {
super(s);
}
}
The cleanest way to throw an exception with the Reactor project is really just to throw it. There are error handling functions that allow you to provide different flows to certain error cases.
The good news is you have several options that provides some flow control for error handling.
Project Reactor provides several of these methods on the Mono object.
doOnError(),onErrorContinue(),onErrorReturn(),onErrorStop(),onErrorMap()
I am not entirely sure what you are trying to achieve with the following sample code.
return Mono.error(new MyException("exception"));
} else {
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good"));
But this looks like a good case for a onErrorMap() since it looks like you are trying to translate some exception here
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good")
.onErrorMap(e -> "translated result");
For our applications, we have our custom base exception extend from RuntimeException. We then have standard exception handling that looks for our custom exception for special handling before returning results back to the end user. This allows us to use normal throws mechanics since we want all exceptions thrown to ripple up the top level of the call.
For performance concerns webflux and reactive are slightly lower performance on a per call basis especially for calls that don't need to do any parallelization. However once load is put onto the system it tends to become more performant primarily related to garbage collection. Overhead from the difference between map and flatMap should be negligible at best.
I'm getting InvocationTarget Exception in my test case. This is the class which I'm trying to test :
public class UpdateHandler implements Handler {
public void process(UE m, UEC u) {
try {
Info info = facade1.queryInfo(string).getInfo();
Index index = facade2.findindex(string2);
if(facade3.isWhitelisted() {
facade2.update(info, index);
}
} catch(UpdateException e) {
//log
}
}
This is my test file
public class TestFile {
#Mock
protected Facade1 facade1;
#Mock
protected Facade2 facade2;
#Mock
protected Facade3 facade3;
private Info info;
private Index index;
#InjectMocks
private UpdateHandler updatehandler;
#BeforeMethod
public void beforeTest() {
MockitoAnnotations.initMocks(this);
}
#Test
public void Test1() {
info = getInfo();
index = getIndex();
updateHandler.process(UEprepare(), null);
Mockito.when(facade1.queryInfo(Mockito.anyString()).getInfo()).thenReturn(getInfo());
Mockito.when(facade2.findindex(Mockito.anyString()).thenReturn(getIndex());
Mockito.when(facade3.isWhitelisted()).thenReturn(true);
Mockito.verify(facade1, Mockito.times(1).update(info, index);
}
}
getInfo() and getIndex() are two methods I created in the test file just to create a sample object of Info and Index. UEprepare is a method to prepare a sample object of UE. UM can be null. I've checked that's not the issue.
The error I'm getting is Null pointer exception. Specifically, the value of facade1.queryInfo(string) is null. It's supposed to be an object of type InfoResult from which I can extract an object of Info. I checked the queryInfo method and that does not throw a NPE anywhere. It only throws exception of type UpdateException which I've already handled in my code in try catch.
When I dug deeper, I found an InvocationTargetException. I can't specifically understand where that exception is coming from but I think it's got something to do with the queryInfo method.
I've initialized mocks for all the facades I'm using and I think I've used InjectMocks correctly as well so I'm stuck on how to debug this.
There are 2 errors in your code:
Order of methods
You have:
call of method under test
setting expectations Mockito.when
verification of expectations Mockito.verify
while it should be
setting expectations Mockito.when
call of method under test
verification of expectations Mockito.verify
Chained expectations
Mockito.when(facade1.queryInfo(Mockito.anyString()).getInfo()).thenReturn(getInfo());
You need additional mock for result of queryInfo call, let's say #Mock QueryInfo queryInfo. Then, you need 2 calls for setting this expectation:
Mockito.when(facade1.queryInfo(Mockito.anyString()).thenReturn(queryInfo);
Mockito.when(queryInfo.getInfo()).thenReturn(getInfo());
When I try to test this method
static void validatePostcode(final String postcode, final String addressLine)
{
if(! hasValidPostcode(postcode, addressLine)) {
throw new InvalidFieldException("Postcode is null or empty ");
}
}
using the following test
#Test
public void testThrowsAnException()
{
assertThatThrownBy(validatePostcode("", "")).isInstanceOf(InvalidFieldException.class);
}
I get this error message in IntelliJ
assertThatThrownBy (org.assertj.core.api.ThrowableAssert.ThrowingCallable) in Assertions cannot be applied to (void)
Same thing with assertThatExceptionOfType.
Is it possible to test that static method actually throws an unchecked exception using AssertJ? What should I change in my test?
As the compilation error demonstrates, that method expects a throwing callable.
#Test
public void testThrowsAnException()
{
assertThatThrownBy(() -> validatePostcode("", "")).isInstanceOf(InvalidFieldException.class);
}
change to this way. you need to pass lambda to test with assertj
assertThatThrownBy(()->validatePostcode("","")).isInstanceOf(InvalidFieldException.class);
I have to throw an exception if a method parameter is a particular value.
The aim is to lock all the method that work with the specific value so I thought to use Spring AOP but I am new with it.
My problem is retrieve the value of method parameter, I create this sample:
Annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAOPAnnotation {
}
AOP class
#Component
#Aspect
public class TestAOP {
#Before("#annotation(TestAOPAnnotation)")
public void logAOP(){
//Make some operations with database and throw exception in a specific case
throw new RuntimeException();
}
}
The method where I use the annotation
#Override
#TestAOPAnnotation
public List<Animals> findByName(String name) throws QueryException {
try{
return animalsRepository.findByName(name);
}catch(Exception e){
throw new QueryException(e);
}
}
and where I catch the exception
#Override
#RequestMapping(value="/test/{name}", method = RequestMethod.GET)
public #ResponseBody List<Animals> findByName(#PathVariable String name){
try{
return databaseAnimalsServices.findByName(name);
}catch(QueryException e){
return null;
}catch(Exception e){
//CATCH AOP EXCEPTION
List<Animals> list = new ArrayList<Animals>();
list.add(new Animals("AOP", "exception", "test"));
return list;
}
}
How can I get the name parameter? I may use another annotation on parameter (or only this annotation) but I don't know how. Can you help me?
EDIT
To catch parameter annotation I may use:
#Before("execution(* *(#Param (*),..))")
but it works only if I know the parameters order instead I need only the annotated parameter.
Otherwise , until now, the best solution is
#Before("#annotation(TestAOPAnnotation) && args(name,..)")
public void logAOP(String name){
System.out.println(name);
throw new RuntimeException("error");
}
but the parameter must be the fist in the signature
You could use an #Around advice which has access to the invocation data.
#Around("#annotation(TestAOPAnnotation)")
public Object logAOP(ProceedingJoinPoint aPoint) throws Throwable {
// First, implement your checking logic
// aPoint.getArgs() may be inspected here ...
if (...) {
throw new RuntimeException(...);
}
// now, actually proceed with the method call
return aPoint.proceed();
}
getArgs() gives you access to the real arguments passed to the method.
You can get the calling arguments from the joinPoint:
#Around(.....)
public Object check(ProceedingJoinPoint joinPoint) {
for (Object object : joinPoint.getArgs()) {
.... add your checks here.
}
return joinPoint.proceed();
}
Note you can not easily get the name of the parameter from the joinPoint (like you can in .NET) but you could check on type and value.
See https://blog.espenberntsen.net/2010/03/20/aspectj-cheat-sheet/ for valid execution patterns.