I am working on Spring Boot 2 to create a microservice. I have a requirement to create an After aspect to execute some piece of code.
#Aspect
#Component
public class FinallyAspect {
#Pointcut("#annotation(finallyEvent)")
public void runFinallyMethod(FinallyEvent finallyEvent) {}
#After("runFinallyMethod(FinallyEvent finallyEvent)")
public void finallyMethod(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
// ...
}
}
Is it possible to get inside finallyMethod whether an exception has occurred or the method returned successfully? I can do it with #AfterReturning and #AfterThrowing annotation, but if there is a way to check if the method has ended in error or success then I can check it in a single function.
It is not possible with After-advice to access whether the method returned successfully or with an exception. There are alternatives...
a) Around-advice (not recommended)
What you want can be manually implemented with a single method using the Around-advice, the most general kind of advice. It is recommended that you use the least powerful advice type that can implement the required behaviour (source). I do not recommend this approach as it can be error-prone in terms of exception handling if implemented the wrong way. For example, if you put your success-code in the try-block, exceptions thrown by this success-code are also caught by the same catch-block as is used for the failure-code. Also, you need to make sure to re-throw the exception and to return the return value of joinPoint.proceed().
This is how could do this properly if you wanted to:
#Around(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public Object finallyMethod(ProceedingJoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
final Object res;
try {
res = joinPoint.proceed();
} catch (Throwable e) {
// code in case of failure
throw e;
}
// code in case of success
return res;
}
b) Clean solution with private method
In this case, I suggest to use AfterReturning-advice and AfterThrowing-advice and then call a private method with a parameter indicating success/error. This is much more readable, does not have the drawbacks of the Around-advice but uses a bit more code.
A boolean (success) is needed
#AfterReturning(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public void finallyMethodReturning(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
finallyMethod(joinPoint, finallyEvent, true);
}
#AfterThrowing(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public void finallyMethodThrowing(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
finallyMethod(joinPoint, finallyEvent, false);
}
private void finallyMethod(JoinPoint joinPoint, FinallyEvent finallyEvent, boolean success) throws Throwable {
if (success) {
// code in case of success
} else {
// code in case of failure
}
}
The Throwable is needed
#AfterReturning(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public void finallyMethodReturning(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
finallyMethod(joinPoint, finallyEvent, null);
}
#AfterThrowing(value = "runFinallyMethod(finallyEvent)", throwing = "t", argNames = "joinPoint,finallyEvent,t")
public void finallyMethodThrowing(JoinPoint joinPoint, FinallyEvent finallyEvent, Throwable t) throws Throwable {
finallyMethod(joinPoint, finallyEvent, t);
}
private void finallyMethod(JoinPoint joinPoint, FinallyEvent finallyEvent, Throwable t) throws Throwable {
if (t == null) {
// code in case of success
} else {
// code in case of failure
}
}
I don't think you will be able to implement this using #After as this annotation can only give you the JoinPoint in context, which has no information about return values.
If you want to handle everything within the same method I think the only alternative is to implement this using #Around, where you can do something before and after a method execution. Your implementation could be:
#Around("runFinallyMethod(FinallyEvent finallyEvent)")
public Object finallyMethod(ProceedingJoinPoint jp, FinallyEvent finallyEvent) throws Throwable {
try {
Object result = jp.proceed();
// do nice stuff with result
return result;
} catch(Throwable throwable) {
// do nice stuff with the exception;
throw throwable;
}
}
Related
Is there any way to write a mockito test case for the particular case.
public void saveStaffInfo(HttpServletResponse response, RegBean regdata, Staffinfo staffType, boolean status)
throws IOException {
if (status)
{
boolean status1 = staffType.insertlogin(regdata);
if(status1) {
response.sendRedirect("registration.jsp?status=success");
}
else {
response.sendRedirect("registration.jsp?status=login_table_error");
}
} else {
response.sendRedirect("registration.jsp?status=failed");
}
}
I did mock the HttpServeletResponse, RegBean,Staffinfo. However, as it is of void type so I cannot use doReturn().when(mockedMethod).(someMethod). So how do I test these lines?
I also need code coverage. I am very new to this.
The test case
#Test
public void testSaveStaffInfo() throws IOException, ServletException{
boolean status =true;
// System.out.println(iStaffInfo.insertlogin(regdata));
Mockito.when(iStaffInfo.insertlogin(regdata)).thenReturn(Boolean.TRUE );
reg.saveStaffInfo(response, regdata, iStaffInfo,status);
}
You need to think what it is you want to test here. What is the "output"? The "output" here is that the method is doing something to your HttpServletResponse, it is calling sendRedirect.
You can verify that certain methods are being called on your mocked (or real) objects with Mockito.verify
I have been converting some code to be asynchronous. The original unit test used the annotation #Test(expected = MyExcpetion.class) but I don't think this will work because the exception I want to assert on is wrapped in java.util.concurrent.ExcutionException . I did try calling my future like this but my assertion is still failing and I don't love that I had to add in return null
myApiCall.get(123).exceptionally((ex) -> {
assertEquals(ex.getCause(),MyCustomException.class)
return null
}
I also tried this flavor but still not working
myApiCall.get(123).exceptionally((ex) -> {
assertThat(ex.getCause())
.isInstanceOF(MyException.class)
.hasMessage("expected message etc")
return null;
}
My API just throws exception if it can't find id. How should I be properly testing this? Can I use that original annotation in anyway?
my api call reaches out to db when run. In this test I am setting up my future to return an error so it doesn't actually try to communicate with anything. the code under test looks like this
public class myApiCall {
public completableFuture get(final String id){
return myService.getFromDB(id)
.thenApply(
//code here looks at result and if happy path then returns it after
//doing some transformation
//otherwise it throws exception
)
}
}
in the unit test I force myService.getFromDB(id) to return bad data so I can test exception and also keep this a unit test don't reach out to db etc.
Let's assume your API throws if called with 0:
public static CompletableFuture<Integer> apiCall(int id) {
return CompletableFuture.supplyAsync(() -> {
if (id == 0) throw new RuntimeException("Please not 0!!");
else return id;
});
}
You can test that it works as expected with the following code (I'm using TestNG but I suspect it won't be too difficult to translate into a JUnit test):
#Test public void test_ok() throws Exception {
CompletableFuture<Integer> result = apiCall(1);
assertEquals(result.get(), (Integer) 1);
}
#Test(expectedExceptions = ExecutionException.class,
expectedExceptionsMessageRegExp = ".*RuntimeException.*Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
result.get();
}
Note that the second test uses the fact that the ExecutionException message will contain the original exception type and message and captures the expectation with a regex. If you can't do that with JUnit, you can call result.get() in a try/catch block and call throw e.getCause(); in the catch block. In other words, something like this:
#Test(expectedExceptions = RuntimeException.class,
expectedExceptionsMessageRegExp = "Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
try {
result.get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
You can try also alternative option:
import org.hamcrest.core.IsInstanceOf;
import org.junit.rules.ExpectedException;
public class Test() {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void myApiCallTest() {
thrown.expect(ExcutionException.class);
thrown.expectCause(IsInstanceOf.instanceOf(MyException.class));
thrown.expectMessage("the message you expected");
myApiCall.get("");
}
}
Assuming that:
public class myApiCall {
public completableFuture get(final String id) {
// ...
throw new ExcutionException(new MyException("the message you expected"))
}
}
Assume that you have a class and you want to test a method which returns a completable future:
public class A {
private final Api api;
public A(Api api) { this.api = api;}
public CompletableFuture<Void> execute(Integer input) {
final CompletableFuture<Void> future = api.execute(input)
.thenApplyAsync(result -> doSomething())
.exceptionally(ex -> doFailure());
return future;
}
}
To test the execution of "doSomething()" then you may use mockito and do the following:
// prepare test
final Api api = mock(Api.class)
final A a = new A(api);
when(api.execute(any(Integer.class)))
.thenReturn(CompletableFuture.completedFuture(null));
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
...
To test "doFailure" do the following:
when(api.execute(any(Integer.class))).thenAnswer(answer -> {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
return future;
});
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
assertTrue(result.isCompletedExceptionally());
that is easy thing doing in junit-4. Are you remember the #RunWith annotation? Yes, write your own TestRunner to intercept the exception before the junit expected exception processor is invoked, for example:
public class ConcurrentRunner extends BlockJUnit4ClassRunner {
public ConcurrentRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected Statement possiblyExpectingExceptions(FrameworkMethod method,
Object test,
Statement next) {
return super.possiblyExpectingExceptions(
method, test, throwingActualException(next)
);
}
private Statement throwingActualException(Statement next) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
next.evaluate();
} catch (ExecutionException | CompletionException source) {
throw theActualExceptionOf(source);
}
}
private Throwable theActualExceptionOf(Exception source) {
return source.getCause() != null ? source.getCause() : source;
}
};
}
}
just annotated with #RunWith(ConcurrentRunner.class) on the test, you needn't change your test code at all. for example:
#RunWith(ConcurrentRunner.class)
public class ConcurrentExpectedExceptionTest {
#Test(expected = IllegalArgumentException.class)
public void caughtTheActualException() throws Throwable {
myApiCall().join();
}
private CompletableFuture<Object> myApiCall() {
return CompletableFuture.supplyAsync(() -> {
throw new IllegalArgumentException();
});
}
}
I would like to annotate some of my test cases with KnownFault - which would do pretty much what expectedException does plus some magic using YouTrack's REST API. I would also like to have an IntermittentFailure attribute which would mean that I'm aware that the test might occasionally fail with [exception] [message] but I wouldn't want this to block the rest of my build chain.
After some research I found that my test class should implement IHookable, then I could have something like this:
#Override
public void run(IHookCallBack callBack, ITestResult result) {
callBack.runTestMethod(result);
if (result.getThrowable().getCause() instanceof IllegalArgumentException){
System.out.println("This is expected.");
result.setThrowable(null);
}
else{
System.out.println("Unexpected exception");
}
}
The problem with this is the actual implementation of invokeHookable:
final Throwable[] error = new Throwable[1];
IHookCallBack callback = new IHookCallBack() {
#Override
public void runTestMethod(ITestResult tr) {
try {
invokeMethod(thisMethod, testInstance, parameters);
} catch (Throwable t) {
error[0] = t;
tr.setThrowable(t); // make Throwable available to IHookable
}
}
#Override
public Object[] getParameters() {
return parameters;
}
};
hookable.run(callback, testResult);
if (error[0] != null) {
throw error[0];
}
Unfortunately that last line means that my test case is going to throw an exception no matter what as the error array is completely out of my hands in the run method.
So, what would be the proper way of intercepting an exception and handling it the way I want to?
What you are trying to do is really interesting. You should try to propose changes on https://github.com/cbeust/testng/pull/
But maybe IHookable is not the best listener you can use. Did you try IInvokedMethodListener?
void afterInvocation(IInvokedMethod method, ITestResult result) {
if (result.getThrowable().getCause() instanceof IllegalArgumentException) {
System.out.println("This is expected.");
result.setThrowable(null);
result.setStatus(SUCCESS); // If you want to change the status
} else {
System.out.println("Unexpected exception");
}
}
I have a well specified interface and against that I write my JUnit tests:
public interface ShortMessageService {
/**
* Creates a message. A message is related to a topic
* Creates a date for the message
* #throws IllegalArgumentException, if the message is longer then 255 characters.
* #throws IllegalArgumentException, if the message ist shorter then 10 characters.
* #throws IllegalArgumentException, if the user doesn't exist
* #throws IllegalArgumentException, if the topic doesn't exist
* #throws NullPointerException, if one argument is null.
* #param userName
* #param message
* #return ID of the new created message
*/
Long createMessage(String userName, String message, String topic);
[...]
}
As you can see the implementation can throw various exceptions for which I have to write tests. My current approach is to write one test method for one possible exception specified in the interface like this:
public abstract class AbstractShortMessageServiceTest
{
String message;
String username;
String topic;
/**
* #return A new empty instance of an implementation of ShortMessageService.
*/
protected abstract ShortMessageService getNewShortMessageService();
private ShortMessageService messageService;
#Rule
public ExpectedException thrown = ExpectedException.none();
#Before
public void setUp() throws Exception
{
messageService = getNewShortMessageService();
message = "Test Message";
username = "TestUser";
topic = "TestTopic";
}
#Test
public void testCreateMessage()
{
assertEquals(new Long(1L), messageService.createMessage(username, message, topic));
}
#Test (expected = IllegalArgumentException.class)
public void testCreateMessageUserMissing() throws Exception
{
messageService.createMessage("", message, topic);
}
#Test (expected = IllegalArgumentException.class)
public void testCreateMessageTopicMissing() throws Exception
{
messageService.createMessage(username, message, "");
}
#Test (expected = IllegalArgumentException.class)
public void testCreateMessageTooLong() throws Exception
{
String message = "";
for (int i=0; i<255; i++) {
message += "a";
}
messageService.createMessage(username, message, topic);
}
#Test (expected = IllegalArgumentException.class)
public void testCreateMessageTooShort() throws Exception
{
messageService.createMessage(username, "", topic);
}
#Test (expected = NullPointerException.class)
public void testCreateMessageNull() throws Exception
{
messageService.createMessage(username, null, topic);
}
[...]
}
So for now I have to define a lot of test methods for that one method defined in the interface and that feels awkward. Can I combine all these exception tests in one test method or what is the best practice?
Unfortunately, the #Test annotation doesn't allow for catching multiple exception types (api reference http://junit.sourceforge.net/javadoc/org/junit/Test.html).
As a first option, I would advocate moving to TestNG. If your team won't allow that, there are few things you can do in JUnit.
Definitely use parameterized test cases so that you don't have to write one test function per test case (http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html). From here, there are a few options.
Group your test data by exception types.
#Test (expected = IllegalArgumentException.class)
public void testIllegalArgumentException(String username, String message, String topic) {}
#Test (expected = NullPointerException.class)
public void testNullPointerException(String username, String message, String topic) {}
Combine the exception types in your method signature. (This is what I recommend) Rough outline below ...
public void testException(String username, String message, String topic, Class<? extends Exception>[] expectedExceptionClasses) {
try {
// exception throwing code
} catch (Exception e) {
boolean found = false;
for (Class<?> expectedException : expectedExceptions) {
if (e instanceof expectedException) {
found = true;
}
}
if (found) {
return;
}
}
Assert.fail();
}
Put all of your tests under the umbrella Exception class (I have a feeling you don't want to do that.).
#Test (expected = Exception.class)
public void testException(String username, String message, String topic) {}
It might not be the best idea to combine them all in one method, since you wouldn't really know which test case threw which exception.
For example, if you had the line
messageService.createMessage(username, null, topic);
which should throw a NullPointerException, but instead it threw an IllegalArgumentException, you don't want that to count as a success.
If you'd like to test all the exceptions of that method in one test case, then a good alternative would be to wrap each exception test in a try..catch block.
For example, you could have
#Test
public void testCreateMessageExceptions() {
// test #1: a null message
try {
messageService.createMessage(username, null, topic);
// if it got this far, that's a problem!
fail();
} catch(NullPointerException e) {
// great, that's what it's meant to do! continue testing
} catch(Exception e) {
// if it threw the wrong type of exception, that's a problem!
fail();
}
// test #2: an empty user
try {
messageService.createMessage("", message, topic);
fail();
} catch(IllegalArgumentException e) {
} catch(Exception e) {
fail();
}
// ...
}
I have some webservices that are developed on axis 1.1, and I need to make a few changes. During this I am fixing up the exception handling code, but I don't know what kind of exception I should throw when there is an error.
I only need to send the message to the client, I don't need to worry about stack traces and custom information in the exceptions. I don't want to deal with extending soapfaults, or providing reasons for the failures, and all that jazz.
#WebMethod
public string[] myMethod() throws ..?.. {
throw new AxisFault(); // not recommended
throw new SOAPFaultException(); // seems overly general
throw new Exception(); // what we have now
}
Is there any right way to do this, or is throw new Exception the right way to go about it?
You may create a custom exception (say FooException) extending Exception annotated with JAX-WS #WebFault.
#WebFault(faultBean = "org.foo.bar.FooFault")
public class FooException extends Exception {
private FooFault fooFault;
public FooException() {
super();
}
public FooException(String message, FooFault fooFault, Throwable cause) {
super(message, cause);
this.fooFault = fooFault;
}
public FooException(String message, FooFault fooFault) {
super(message);
this.fooFault = fooFault;
}
public FooFault getFaultInfo() {
return fooFault;
}
}
// this is org.foo.bar.FooFault
public class FooFault {
// POJO
}
And then you declare that your web method throws that exception.
#WebMethod
public string[] myMethod() throws FooException {
// do some stuff
throw new FooException();
// or with a cause
try {
// something dangerous
} catch (Exception e) {
throw new FooException("Shit happens", new FooFault(), e);
}
// or like this
throw new FooException("Foo", new FooFault());
}
JAX-WS should do the rest.