//
you're reading...
TestNG

Working with Threads in TestNG

Sometime back, me and my friend were trying to play around with Threads in @Test annotated TestNG methods and we found something which to me was a good learning exercise. So just thought of sharing that here, in-case someone needs a similar thing. I learnt that TestNG works using Reflection. Now reflection suffers from one setback when used with Threads. For example, I have a main method (public static void main(String[] args)) which is spawning a new child thread using reflection. Now for some reason the new child thread throws an exception, then main method would never get to know about this exception at all !! Why ?? Because the new thread was spawned via Reflection. Because of this setback in Java, TestNG also ends up inheriting this limitation. But I learnt that there is a way in which you can get past this behavior. The way to circumvent this problem is to use ExecutorService (as suggested by Cedric Beust).Here’s a working example, that has 4 test methods. The below test methods use ExecutorService for Thread management and as such always pass.

  • testUsingExecutorService()
  • testUsingExecutorServiceWithException()

However the below test methods spawn Threads in the normal way and as such one of the tests will always fail.

  • testUsingThreads()
  • testUsingThreadsWithExceptions() – This method would always fail even though it expects a RuntimeException because the main thread wherein the Test method runs never gets to know the exceptions being thrown in the child thread it spawns.
package testng.samples;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.testng.annotations.Test;
public class ThreadExecutorServiceDemo {
    private static final String ERROR_MSG = "From thread you asked me throw an exception";
    @Test
    public void testUsingExecutorService() throws InterruptedException, ExecutionException {
        MyCallableService service = new MyCallableService(false);
        Future<String> returnValue = Executors.newSingleThreadScheduledExecutor().submit(service);
        System.out.println(returnValue.get());
    }
    @Test(expectedExceptions = ExecutionException.class, expectedExceptionsMessageRegExp = ".*" + ERROR_MSG + ".*")
    public void testUsingExecutorServiceWithException() throws InterruptedException, ExecutionException {
        MyCallableService anotherService = new MyCallableService(true);
        Future<String> anotherReturnValue = Executors.newSingleThreadScheduledExecutor().submit(anotherService);
        System.out.println(anotherReturnValue.get());
    }
    @Test
    public void testUsingThreads() throws InterruptedException {
        MyThreadService mt = new MyThreadService(false);
        mt.start();
        while (mt.isAlive() == true) {
            Thread.sleep(10000);
        }
        System.out.println(mt.getServiceName());
    }
    @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = ERROR_MSG)
    public void testUsingThreadsWithExceptions() throws InterruptedException {
        MyThreadService mt = new MyThreadService(true);
        mt.start();
        while (mt.isAlive() == true) {
            Thread.sleep(10000);
        }
        System.out.println(mt.getServiceName());
    }
    public class MyThreadService extends Thread {
        private boolean throwException;
        private String serviceName;
        public String getServiceName() {
            return serviceName;
        }
       public MyThreadService(boolean throwException) {
            this.throwException = throwException;
        }
        public void run() {
            try {
                sleep(25000);
                this.serviceName = "TestNG threaded Service";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (throwException) {
                throw new RuntimeException(ERROR_MSG);
            }
        }
    }
    public class MyCallableService implements Callable<String> {
        private boolean throwException;
        public MyCallableService(boolean throwException) {
            this.throwException = throwException;
        }
        @Override
        public String call() throws Exception {
            Thread.sleep(25000);
            if (throwException) {
                throw new RuntimeException(ERROR_MSG);
            }
            return "Callable Service Invoked";
        }
    }
}
Output:

[TestNG] Running:
  C:\Users\krmahadevan\AppData\Local\Temp\testng-eclipse--667883055\testng-customsuite.xml

Callable Service Invoked
TestNG threaded Service
Exception in thread "Thread-2" java.lang.RuntimeException: From thread you asked me throw an exception
	at testng.samples.ThreadExecutorServiceDemo$MyThreadService.run(ThreadExecutorServiceDemo.java:71)
TestNG threaded Service
PASSED: testUsingExecutorService
PASSED: testUsingExecutorServiceWithException
PASSED: testUsingThreads
FAILED: testUsingThreadsWithExceptions
org.testng.TestException: 
Expected exception java.lang.RuntimeException but got org.testng.TestException: 
Method ThreadExecutorServiceDemo.testUsingThreadsWithExceptions()
[pri:0, instance:testng.samples.ThreadExecutorServiceDemo@4fbc9499] should have thrown an exception of 
class java.lang.RuntimeException
	at org.testng.internal.Invoker.handleInvocationResults(Invoker.java:1485)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1233)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
	at org.testng.TestRunner.privateRun(TestRunner.java:768)
	at org.testng.TestRunner.run(TestRunner.java:617)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
	at org.testng.SuiteRunner.run(SuiteRunner.java:240)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:87)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1188)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1113)
	at org.testng.TestNG.run(TestNG.java:1025)
	at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:109)
	at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:202)
	at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:173)
Caused by: org.testng.TestException: 
Method ThreadExecutorServiceDemo.testUsingThreadsWithExceptions()
[pri:0, instance:testng.samples.ThreadExecutorServiceDemo@4fbc9499] should have thrown an exception of 
class java.lang.RuntimeException
	at org.testng.internal.Invoker.handleInvocationResults(Invoker.java:1500)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:751)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:894)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1219)
	... 16 more


===============================================
    Default test
    Tests run: 4, Failures: 1, Skips: 0
===============================================


===============================================
Default suite
Total tests run: 4, Failures: 1, Skips: 0
===============================================
Advertisements

Discussion

5 thoughts on “Working with Threads in TestNG

  1. I have a test which uses a reflection, i want to execute this test in two browsers using selenium and testng, i am confused, pls help in doing this.

    Posted by uday | August 17, 2012, 9:04 pm
  2. @Uday, did you achieve working with threads in NG ?

    Posted by Soumya Mukherjee | August 16, 2016, 12:12 pm
  3. I can’t get this to complie. Get “The public type ThreadExecutorServiceDemo must be defined in its own file” error. None of the things mentioned when I googled seems to work.

    Posted by Karen | December 9, 2016, 7:33 am
    • Karen why don’t you post your code on gist.github.com or pastebin and share a link ? All samples that I have here are tested ones. Btw I hope that your Java class ThreadExecutorServiceDemo resides in its own Java class called ThreadExecutorServiceDemo.java

      Posted by Confusions Personified | December 9, 2016, 7:41 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: