I was going to increase the code coverage. In the process, I was unable to test the catch block of a specific method. I was trying to force exceptions to the method call.
RuleSchedule.java
public class RuleScheduler
{
private boolean enabled;
private Integer batchSize;
#Autowired
private ExternalService externalService;
public void executeRuleValidation()
{
if (enabled)
{
try
{
StopWatch stopWatch = new StopWatch();
stopWatch.start();
externalService.executeRuleValidationForProposal(batchSize);
stopWatch.stop();
log.info("Total time taken for RuleValidation:{} for batchSize :{}",
stopWatch.getTotalTimeSeconds(), batchSize);
}
catch (Exception ex)
{
// System.out.println("~~~~~~CATCH~~~~~~");
log.error("Rule exception :{}", ex);
}
}
}
}
I was trying different ways to throw exceptions to get into the catch block of the above code, but was unable to do so. And here is my Test class. Even the batchsize is accepting null values.
RuleScheduleTest.java
#RunWith(MockitoJUnitRunner.class)
public class RuleSchedulerTest
{
#Mock
private ExternalService externalService;
#InjectMocks
private RuleScheduler RuleScheduler;
#Before
public void init()
{
ReflectionTestUtils.setField(RuleScheduler, "enabled", true);
ReflectionTestUtils.setField(RuleScheduler, "batchSize", 5);
}
#Test
public void testExecuteRuleValidation()
{
RuleScheduler.executeRuleValidation();
}
}
One possibility would be to configure your mock externalService instance to throw an exception. You should be able to then verify the interaction with the mock. Something like the following:
#Test
public void testExecuteRuleValidation(){
// configure your mock 'externalService' instance to throw an exception
when(externalService.executeRuleValidationForProposal(any(Integer.class))).thenThrow(IllegalArgumentException.class);
RuleScheduler.executeRuleValidation();
// now verify mock interaction
verify(externalService, times(1)).executeRuleValidationForProposal(any(Integer.class));
}
Related
I am trying to unit test Class A, where Class A is as follows
Class A{
private final classB = new ClassB();
public Void test(ScheduledEvent scheduledEvent, Context context) {
try {
Thread thread2 = new Thread(() -> doHandleRequest());
thread2.start();
thread2.join(3000);
if (thread2.isAlive()) {
thread2.interrupt();
// sleep for 30 seconds to flush any logs or CFN metrics.
Thread.sleep(30000);
}
} catch (InterruptedException ex) {
}
}
void doHandleRequest() {
try {
classB.sweep();
} catch(Exception ex) {
log.error("Exception in SweepThread while sweeping and deleting lambdas", ex);
}
}
}
Class B{
public void sweep(){
// do something;
}
I want to unit test Class A scenario where thread2.isAlive() condition is true and it goes to that if block.
First, you need to change how you create ClassB object to allow mocking, it can not be done when objects get created every time.
You can do that like this
public class ClassA {
private final ClassB b;
// this will allow you to inject mock from outside, as it's final, can be initialized only via a constructor.
public ClassA(ClassB b){
this.b = b;
}
// your remaining code
}
And now, in your test case, you need to inject mocks.
#Test
public void test() throws InterruptedException {
ClassB classB = Mockito.mock(ClassB.class);
ClassA classA = new ClassA(classB);
MockitoAnnotations.initMocks(this); // this will initialize mocks
//above can be skipped if you are using annotations for the same
Mockito.stubVoid(classB)
.toAnswer(invocationOnMock -> {
Thread.sleep(4000);
return null;
}).on().sweeps();
parent.test(null, null);
}
To make sure, your thread is alive after join, you can add delay in mock method of classB.
As your method returns void, we need to use stubVoid, otherwise it will be like this.
Mockito.when(mock.method(/* args, if, any */)).thenAnswer(mock -> {
Thread.sleep(delayInMilliseconds);
return desiredValue;
})
I have an EJB Interceptor which should catch and process all exception which was thrown in transaction:
public class ExceptionsInterceptor {
#AroundInvoke
public Object intercept(final InvocationContext invocationContext) throws Exception {
try {
return invocationContext.proceed();
} catch (Exception e) {
throw new MyException(e);
}
}
}
But if during hibernate flush thrown PesistenceException because of constraint violation I can't catch this exception. I understood
that hibernate do flush after my Interceptor finish work.
But I need catch all exception.
To implement this I've decorate this EJB by other EJB.
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED_NEW)
public class TargetServiceBean implements TargetServiceLocal {
#Override
public boolean method1(Integer digit) {
.. some code which my generate exception..
}
}
#Stateless
#Interceptors(ExceptionsInterceptor.class)
public class TargetServiceBean implements TargetServiceDecorator {
#Inject
private TargetServiceLocal service;
#Override
public boolean method1(Integer digit) {
service.method1(digit);
}
}
It works but looks like workaround and I don't like this solution. So basically I need to run interceptor out of transaction. How can I do this?
I try to write a very simple code to test #Transactional, but it won't rollback when I use Propagation.REQUIRED. Here is the code.
#Component
public class A {
private JdbcTemplate jdbcTemplate;
#Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Transactional(propagation=Propagation.REQUIRED)
public void add(Person person) throws Exception {
try {
String sql = "insert into person (id, name) values(?,?)";
jdbcTemplate.update(sql, new Object[{person.getId(),person.getName()});
} catch (Exception e) {
throw new RuntimeException();
}
#Transactional(propagation=Propagation.REQUIRED)
public void delete(String id) throws Exception {
throw new RuntimeException();
***throw a RuntimeException on purpose***
}
}
public class cases {
#Transactional
public static void testPro() throws Exception {
try {
AbstractApplicationContext aac = new ClassPathXmlApplicationContext("beans.xml");
A a = (A) aac.getBean("a");
a.add(***a random person***);
a.delete("99");
} catch (Exception e) {
throw new RuntimeException();
}
}
#Test
public void test() throws Exception {
testPro();
}
}
When I test add() method alone by creating a new RuntimeException(), it will rollback. This is what I expected. However, when I run the test() method, the add() method won't rollback when delete() throws a new RuntimeException. It means the add() and delete() are not in a same transaction, but what I want is all the things to be rollback. Please help.
#Transactional on testPro() has no effect for 3 separate reasons:
testPro() is static.
Call is internal from test() in same class.
Instance of class cases not created by Spring.
That means that add() and delete() are running in two separate transactions.
To prove it, try changing the propagation on delete() to MANDATORY. It will now throw exception saying that transaction is not in progress (or something to that effect).
I am looking to implement the following functionality.
I need a Junit test class which scans list of classes in a package and verifies whether every method contains begin and close transactions. Any pointers in this regard will is appreciated.
I'm not going to answer your question directly because I think you are not going the right way. A better design would ensure you the property you want to test. You can do something like :
public interface Transaction {
void initiate() throws Exception;
void execute() throws Exception;
void rollBack();
void close();
}
public TransactionManager {
public void executeTransaction(Transaction transaction) {
try {
transaction.initiate();
transaction.execute();
} catch (Exception e) {
transaction.rollBack();
} finally {
transaction.close();
}
}
}
And then, it becomes easy to test :
public class TestTransaction implements Transaction {
private boolean initiated, executed, rollBacked, closed;
#Override
public initiate() { initiated = true; }
// ...
}
public class FailingTestTransaction extends TestTransaction {
#Override
public execute() throws Exception {
super.execute();
throw new Exception("Voluntary failure");
}
// ...
}
public TransactionManagerTest {
private TransactionManager transactionManager;
#Before
public void setUp() {
this.transactionManager = new TransactionManager();
}
#Test
public void initiateAndCloseOnNormalExecution() {
TestTransaction transaction = new TestTransaction();
transactionManager.executeTransaction(transaction);
assert(transaction.isInitiated() && transaction.isClosed());
}
#Test
public void initiateRollbackAndCloseOnFailure() {
TestTransaction transaction = new FailingTestTransaction();
transactionManager.executeTransaction(transaction);
assert(transaction.isInitiated() && transaction.isRollbacked && transaction.isClosed());
}
}
#Override
#Async
public void asyncExceptionTest() {
int i=1/0;
}
How can I log this using Spring Async framework without having to put try catch around every async method? It doesn't seem to pass to the DefaultUncaughtExceptionHandler like normal.
#Async methods can be configured with a custom Executor to log any thrown exceptions.
The following code implements this pattern. Any method tagged with #Async will use the Executor returned by the method public Executor getAsyncExecutor(). This returns the HandlingExecutor which takes care of all logging (in this case it just prints the word "CAUGHT!" but you can replace with logging.
#Configuration
#EnableAsync
public class ExampleConfig implements AsyncConfigurer {
#Bean
public Runnable testExec() {
return new TestExec();
}
#Override
public Executor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return new HandlingExecutor(executor);
}
}
public class HandlingExecutor implements AsyncTaskExecutor {
private AsyncTaskExecutor executor;
public HandlingExecutor(AsyncTaskExecutor executor) {
this.executor = executor;
}
#Override
public void execute(Runnable task) {
executor.execute(task);
}
#Override
public void execute(Runnable task, long startTimeout) {
executor.execute(createWrappedRunnable(task), startTimeout);
}
#Override
public Future<?> submit(Runnable task) {
return executor.submit(createWrappedRunnable(task));
}
#Override
public <T> Future<T> submit(final Callable<T> task) {
return executor.submit(createCallable(task));
}
private <T> Callable<T> createCallable(final Callable<T> task) {
return new Callable<T>() {
#Override
public T call() throws Exception {
try {
return task.call();
} catch (Exception e) {
handle(e);
throw e;
}
}
};
}
private Runnable createWrappedRunnable(final Runnable task) {
return new Runnable() {
#Override
public void run() {
try {
task.run();
} catch (Exception e) {
handle(e);
}
}
};
}
private void handle(Exception e) {
System.out.println("CAUGHT!");
}
}
Update: Since Spring 4.1
Since Spring 4.1 It is possible to have an AsyncUncaughtExceptionHandler for #Async void methods.
Spring Reference Doc, Chapter 34.4.5 Exception management with #Async
... With a void return type however, the exception is uncaught and cannot be transmitted. For those cases, an AsyncUncaughtExceptionHandler can be provided to handle such exceptions.
By default, the exception is simply logged. A custom AsyncUncaughtExceptionHandler can be defined via AsyncConfigurer or the task:annotation-driven XML element.
(This feature was introduced after DD raised an impovement request: https://jira.spring.io/browse/SPR-8995 , see comments of this answer)
Before Spring 4.1
Looks like an missing feature how to handle exceptions of an void returning #Async Method. (I can not find any hint in the reference or java doc)
What I can imagine of an solution: Try to use AspectJ to write some kind of wrapper arround all #Async methods that log the exceptions.
For the log term, I would recommend to create an freature request in the spring bug tracker.
First off all, you should create a custom exception handler class like following;
#Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(AsyncExceptionHandler.class);
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("Unexpected asynchronous exception at : "
+ method.getDeclaringClass().getName() + "." + method.getName(), ex);
}
}
After that, you should set your customized exception handler class in your configuration like following;
#Configuration
#EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
#Autowired
private AsyncExceptionHandler asyncExceptionHandler;
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler;
}
}
Note : Injectable exception handler is an option. You can create a new instance for every exception. My advice is using Injection for exception handler class, because spring's default scope is singleton so there is no need to create new instance for every exception.
You can use standard Spring AOP approach
#Aspect
#Component
#Slf4j
public class AsyncHandler {
#Around("#annotation(org.springframework.scheduling.annotation.Async)")
private Object handle(ProceedingJoinPoint pjp) throws Throwable {
try {
Object retVal = pjp.proceed();
return retVal;
} catch (Throwable e) {
log.error("in ASYNC, method: " + pjp.getSignature().toLongString() + ", args: " + AppStringUtils.transformToWellFormattedJsonString(pjp.getArgs()) + ", exception: "+ e, e);
throw e;
}
}
}