I'm doing some testing of my stateless session beans from a junit class so the flow goes something like this.
Junit test method calls a business method in bean A. This method throws a CustomException.
Bean A business method calls bean B business method. This method also throws a CustomException.
Bean B calls a remote Bean C which throws a BeanCException. Bean B catches an AccountBadFormatException, wraps it in CustomException and throws is back to Bean A.
From Bean A CustomException is rethrown back to JUnit calling code. When I catch CustomException in JUnit and look at it, there is no AccountBadFormatException inside. The cause reads "CustomException" and the stacktrace is gone. But If I look at it in Bean A just before it gets thrown to JUnit the nested exception is there. Why would this happen?
JUnit class:
#Test
public void testGetResult() {
setupContext();
Result result = null;
try {
result = (Result) serviceInterface.getResult("000001", "01011970");
} catch (CustomException e) {
System.out.println("CustomException getCause() in JUnit: " + e.getCause().toString());
fail();
}
assertTrue((result.getReturnCode() == ReturnCode.OK));
}
Bean A:
#Override
public Result getResult(String clientID, String dob) throws CustomException {
Result result = new Result(ReturnCode.ERROR);
boolean isMatched = false;
try {
isMatched = Lookup.getUtilityService().isIdentMatched(clientID, dob);
} catch (CustomException e) {
System.out.println("CustomException getCause() in Bean A: " + e.getCause().toString());
throw e;
}
if (isMatched) {
result.setReturnCode(ReturnCode.OK);
}
return result;
}
Bean B:
#Override
public boolean isIdentMatched(String clientID, String dob) throws CustomException {
IdentRequest request = new IdentRequest(clientID);
ClientSummary response = null;
// retrieve the data
try {
response = getRetriever().getClientSummaryView(request)
.getClientSummary();
} catch (XrefAccountNumberException e) {
throw new CustomException(e.getMessage(), e);
} catch (AccountNotFoundException e) {
throw new CustomException(e.getMessage(), e);
} catch (AccountBadFormatException e) {
throw new CustomException(e.getMessage(), e);
} catch (ExclusiveLockException e) {
throw new CustomException(e.getMessage(), e);
} catch (RemoteException e) {
throw new CustomException(e.getMessage(), e);
} catch (ValidationException e) {
throw new CustomException(e.getMessage(), e);
}
return response.isMismatch();
}
The output of the print statement in Bean A is: "CustomException getCause() in Bean A: ca.gc.cra.iica.iasi.common.exceptions.AccountBadFormatException"
The print statement in JUnit is: "CustomException getCause() in JUnit: ca.gc.cra.fltr.filemyreturn.business.exceptions.CustomException"
Related
I need to write a simple code tester program, but I got stuck comparing the given error class with the test expected class. I am supposed to use reflection in this exercise.
I have my code testing class:
public class TestRunner {
private String result = "";
public void runTests(List<String> testClassNames) {
for (String testClassName : testClassNames) {
Class<?> clazz;
try {
clazz = Class.forName(testClassName);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("No such class.");
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getAnnotation(MyTest.class) != null) {
if (testClassName.equals("reflection.tester.ExampleTests1")) {
result += method.getName() + "() - ";
ExampleTests1 instance = new ExampleTests1();
try {
// if null, result = OK
method.invoke(instance);
result += "OK\n";
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
// if error is caught result = FAILED
result += "FAILED\n";
}
} else {
// the second class. should only return "OK" if the error is implemented from the exception class
result += method.getName() + "() - ";
ExampleTests2 instance = new ExampleTests2();
try {
method.invoke(instance);
result += "FAILED\n";
} catch (RuntimeException e) {
Throwable original = e.getCause();
Object expected = method.getReturnType();
if (original.getClass().isAssignableFrom(expected.getClass())) {
result += "OK\n";
} else {
result += "FAILED\n";
}
} catch (InvocationTargetException | IllegalAccessException e) {
result += "ERROR\n";
}
}
}
}
}
}
}
Also have two test classes. In the first one there is only one rule, if the test won't throw an exception the test should pass, and it is working. The second class is more complicated. If the thrown error class is implemented or same to the expected error class then the test should pass and OK should be added to the result. Currently my code won't catch RunTimeException at all and moves to the last catch block. How can I fix this?
I will also add the test class for more information.
public class ExampleTests2 {
#MyTest(expected = RuntimeException.class)
public void test3() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test4() {
throw new RuntimeException();
}
#MyTest(expected = IllegalStateException.class)
public void test5() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test6() {
}
public void helperMethod() {
}
}
test3() and test5() should pass, test4() and test6() should fail, helperMethod() won't be checked because I only need to use the tests with #MyTest annotation.
JUnit has an assertThrows method that checks that an Exception is thrown. It has a method signature of
static <T extends Throwable> assertThrows​(Class<T> expectedType, Executable executable){}
Here's the documentation: https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html#assertThrows(java.lang.Class,org.junit.jupiter.api.function.Executable)
and here's how JUnit implements it:
https://github.com/junit-team/junit5/blob/main/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java
I know it is required that in a non-void method, return or throw is a must.
But I don't like the dummy return in catch block in such case:
public int call() throws Exception {
try {
return calcMethod();
} catch (Exception e) {
process(e);
return 0;
}
}
protected void process(Exception e) throws xxxException {
if ( isTypeAException(e) ) { throw new TypeAException() ; }
else if ( isTypeBException(e) ) { throw new TypeBException() ; }
else ( isTypeCException(e) ) { throw new TypeCException() ; }
}
...
process will certainly throws an exception, then why return is still required in catch block?
In one sense, throwing the exception in process() is to be construed as "a problem with processing", which is also not what you mean.
As you want the exception to be raised by call(), so the solution here is to make process() an exception factory:
public int call() throws Exception {
try {
return calcMethod();
} catch (Exception e) {
throw process(e);
}
}
protected xxxException process(Exception e) throws xxxException {
if (isTypeAException(e))
return new TypeAException();
else if (isTypeBException(e))
return new TypeBException();
else
return new TypeCException();
}
I have Hystrix commands in my class which I need to test. I am able to mock all the code except the fallback. To execute the fallback, I need to make my hystrix wrapped method to throw a timeout exception. I don't get how to do that. Can someone help me with it? I tried opening the circuit with #Enablecircuitbreaker on the test class, but that didn't invoke any Hystrix exception :(
#Mock
private MDMConnectorService service;
#InjectMocks
private AIAUtilities aiaUtilities;
#Test
public void testFetchCustomerAccountDetailsHystrixTimeoutException() throws Exception {
try {
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.AIAClientCommand.circuitBreaker.forceOpen", "true");
Mockito.when(service.fetchCustomerAccount(any(GetCustomerAccountType.class))).thenReturn(getTestAIARecord());
GetCustomerAccountResponseType responseType = aiaUtilities
.fetchCustomerAccountDetails(accountNumber);
Assert.assertFalse(true);// if the flow came here, the test case has failed
} catch (Exception ex) {
if (ex instanceof DataAccessException) {
assertEquals(Constants.ERRCODE_AIA_QUERY_TIMED_OUT,
((DataAccessException) ex).getErrorCode());
} else {
throw ex;
}
}
finally {
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.AIAClientCommand.circuitBreaker.forceOpen", "false");
}
}
In this test, the command wrapped by hystrix is being called at
GetCustomerAccountResponseType responseType = aiaUtilities
.fetchCustomerAccountDetails(accountNumber);
The code of AIAUtilities having the hystrix command and corresponding fallback is
#HystrixCommand(commandKey = "AIAClientCommand", fallbackMethod = "aiaClientCommandFallback")
public GetCustomerAccountResponseType fetchCustomerAccountDetails(String accountNumber)
throws DataAccessException {
GetCustomerAccountResponseType response;
try {
if (generalUtil.isObjectEmpty(authHeader)) {
authHeader = iamUtilities.createAuthHeaderAndRenewOfflineTicket();
}
factory = getFactory();
request = getRequest();
accountNumberType = getAccountNumberType();
accountNumberType.setValue(accountNumber);
request.setCustomerAccountNumber(accountNumberType);
request.setSourceId(Constants.VAL_QUICKBASE_SOURCE_AIA);
serviceClass = getServiceClass();
service = getService();
provider = getProvider();;
provider.getRequestContext().put("Authorization", authHeader);
provider.getRequestContext().replace("SOAPAction", "fetchCustomerAccount");
provider.getRequestContext().put("Content-Type", "text/xml");
response = service.fetchCustomerAccount(request);
} catch (DataAccessException e) {
throw e;
}
catch (Exception e) {
if(e instanceof HystrixRuntimeException && e.getCause() instanceof TimeoutException) {
DataAccessException dataAccessException = (DataAccessException) ((HystrixRuntimeException) e)
.getFallbackException().getCause();
throw new DataAccessException(dataAccessException.getErrorCode(),
"Exception in validateLicense.fetchCustomerAccountDetails::" + e.getMessage(),e);
}
else
throw new DataAccessException(Constants.ERRCODE_AIA_EXCEPTION,
"Exception in validateLicense.fetchCustomerAccountDetails:::" + e.toString(), e);
}
return response;
}
private GetCustomerAccountResponseType aiaClientCommandFallback(String accountNumber, Throwable e)
throws DataAccessException {
logger.error("Inside AIAClientCommandFallback : Error is ::" + e.toString());
if(e instanceof HystrixTimeoutException)
throw new DataAccessException(Constants.ERRCODE_AIA_QUERY_TIMED_OUT,
"Exception in AIAClientCommandFallback::" + e.toString(),e);
else if(e instanceof DataAccessException)
throw (DataAccessException)e;
else
throw new DataAccessException(Constants.ERRCODE_AIA_EXCEPTION,
"Inside AIAClientCommandFallback : Error is ::" + e.toString(), e);
}
Instead of returning something in your mocked fetchCustomerAccount just throw an Exception there via thenThrow:
Mockito.when(service.fetchCustomerAccount(any(GetCustomerAccountType.class))).thenThrow(new RuntimeException("Timeout"));
The architecture of my application is like this:
Main classe -> ServiceBean -> Manager -> DAO.
I am throwing an exception in my DAO:
catch (HibernateException he) {
throw new RemuRuntimeLoggableException(he, RuntimeLoggableException.HIBERNATE_UNKNOWN);
}
Then in Manager I catch the exception as below:
catch (RuntimeLoggableException e) {
log.info(e.getMessage());
e.printStackTrace();
throw new RuntimeLoggableException(e, RuntimeLoggableException.HIBERNATE_UNKNOWN);
And in my ServiceBean, I have this:
catch (RuntimeLoggableException e) {
log.info(e.getMessage());
e.printStackTrace();
throw new RemoteException();
In my main class, I have caught the exception like this:
catch (RemoteException e) {
log.info(prefixeLog + " Error");
log.info(e.getMessage());
I also have an interface Service.java. ServiceBean implements this interface and the method concerned here is declared as below in the interface, Service.java:
public void calculate( boolean flag )
throws java.rmi.RemoteException;
The problem I am getting is that the exception RemoteException from the ServiceBean, is not caught in the main class. And I can't modify the interface Service.java as it is automatically generated by XDoclet. Any idea of how to do this please?
In my Service.java, the method is declared like this:
public void calculate( boolean flag )
throws java.rmi.RemoteException;
And in my class it is declared as below:
public static void main(String[] args) throws RuntimeLoggableException {
try {
log.info("Start" + prefixeLog);
serviceBean.calculate(true);
log.info("End" + prefixeLog);
} catch (RemoteException e) {
log.info(prefixeLog + " Error");
log.info(e.getMessage());
}
finally {
InitFramework.stopFramework(FrameworkFacade.BATCH);
System.exit(retour);
}
}
And in my serviceBean:
public void calculate(boolean flagExclurePlansPerimes) throws RemoteException {
You are logging the message of the RemoteException but you are thrown a RemoteException that is constructed without a message.
I am trying to set a number of Enums to default value I am using the following method:
private void checkEnum(Field field, String setMethod) {
// TODO Auto-generated method stub
try {
String className = Character.toUpperCase(field.getName().charAt(0)) +
field.getName().substring(1);
Class<?> cls = Class.forName("com.citigroup.get.zcc.intf." + className);
Object[] enumArray = cls.getEnumConstants();
//set to the last Enum which is unknown
invoke(setMethod, enumArray[enumArray.length - 1] );
} catch(Exception e) {
System.out.println(e.toString());
}
}
The problem is actually setting the Enum. I have extracted the enum type but to then call the MethodInvoker. Passing in the Enum object is proving a problem. All the enums have the following as the last element of the enum array.
EnumName.UNKNOWN
However this is not being set via the invoke method which looks like:
private Object invoke(String methodName, Object newValue) {
Object value = null;
try {
methodInvoker.setTargetMethod(methodName);
if (newValue != null) {
methodInvoker.setArguments(new Object[]{newValue});
} else {
methodInvoker.setArguments(new Object[]{});
}
methodInvoker.prepare();
value = methodInvoker.invoke();
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
} catch (java.lang.reflect.InvocationTargetException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
}
return value;
}
So I'm lost as to why the
invoke(setMethod, enumArray[enumArray.length -1] );
Is not setting my Enum
I attempted to get your code running. The methodInvoker.prepare() call was throwing:
java.lang.IllegalArgumentException: Either 'targetClass' or 'targetObject' is required
So I added in the class missing parameter and the code works, if I understand your use case.
You appear to be setting a static field whose name must be the name of an Enum class under com.citigroup.get.zcc.intf with the first character in the field name downcased.
Here is my modified code:
public void checkEnum(Field field, String setMethod, Class clazz) {
try {
String className = Character.toUpperCase(field.getName().charAt(0)) +
field.getName().substring(1);
Class<?> cls = Class.forName("com.citigroup.get.zcc.intf." + className);
Object[] enumArray = cls.getEnumConstants();
//set to the last Enum which is unknown
invoke(setMethod, enumArray[enumArray.length - 1], clazz);
} catch (Exception e) {
System.out.println(e.toString());
}
}
private Object invoke(String methodName, Object newValue, Class clazz) {
Object value = null;
try {
MethodInvoker methodInvoker = new MethodInvoker(); // this was missing
methodInvoker.setTargetMethod(methodName);
methodInvoker.setTargetClass(clazz); // This was missing
if (newValue != null) {
methodInvoker.setArguments(new Object[]{newValue});
} else {
methodInvoker.setArguments(new Object[]{});
}
methodInvoker.prepare();
value = methodInvoker.invoke();
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(), e);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(), e);
} catch (java.lang.reflect.InvocationTargetException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method invocation failed. " + e.getMessage(), e);
}
return value;
}
}
My test code resembled (Show is an enum class of mine, MethodNameHelper has been previously posted to StackExchange):
public class StackExchangeTestCase {
protected static final Logger log = Logger.getLogger(StackExchangeTestCase.class);
public static Show show;
public static void setShow(Show newShow) {
show = newShow;
}
#Test
public void testJunk() throws Exception {
Method me = (new Util.MethodNameHelper(){}).getMethod();
Class<?> aClass = me.getDeclaringClass();
Field att1 = aClass.getField("show");
show = null;
methodNameHelper.checkEnum(att1, "setShow", aClass);
System.out.println(show); // worked
}
}