mCs
mCs

Reputation: 2911

Execute set of test methods in with multiple concurrent threads

What would be a JUnit based code to run this 3 methods each as 10 concurrent threads.

@RunWith(SpringJUnit4ClassRunner.class
@SpringBootTest
public class TestClass {


    @Test
    public void readFromDBOneRecord(){
       try {
         dbService.findOneByID("1");
       } catch (Exception error) {
             Assert.fail("Unexpected error occured .");
       }
    }

    @Test
    public void writeToDBOneRecord(){
       try {
             dbService.save(entity.builder()
                            .setID("1").setName("John").build())
       } catch (Exception error) {
             Assert.fail("Unexpected error occured .");
       }
    }

    @Test
    public void deleteDbRecord(){
       try {
          dbService.delete("1");
       } catch (Exception error) {
             Assert.fail("Unexpected error occured .");
       }
    }
}

In some cases some of the methods would throw exceptions. Like if the delete being executed before writeToDBOneRecord. So the sequence would be say for only 3 threads per method e.g.:

OperationNr|| OperationName || [ThreadNr/total threads per method]OperationType

     1.        write        [2/3]w
     2.        read         [1/3]r
     3.        read         [3/3]r
     4.        delete       [2/3]d
     5.        read         [2/3]r
     6.        delete       [3/3]d ->exception no record
     7.        write        [1/3]w
     8.        write        [3/3]w ->exception record already present
     9.        delete       [1/3]d

What would the code for executing this 3 test methods each in 10 concurrent threads (30 in total)?

Upvotes: 5

Views: 3625

Answers (1)

Nicolas Filotto
Nicolas Filotto

Reputation: 44965

As you want to do everything in parallel, I would mix everything and rely on CountDownLatch instances to synchronize the threads as next:

@Test
public void testMultiThreading() throws Exception {
    // Total of reader threads
    int reader = 5;
    // Total of writer threads
    int writer = 3;
    // Total of remover threads
    int remover = 1;
    // CountDownLatch used to release all the threads at the same time
    final CountDownLatch startSignal = new CountDownLatch(1);
    // CountDownLatch used to be notified when all threads did their task
    final CountDownLatch doneSignal = new CountDownLatch(reader + writer + remover);
    // List in which we collect all the errors
    final List<Exception> errors = Collections.synchronizedList(new ArrayList<>());
    // Create all the reader threads and start them
    for (int i = 0; i < reader; i++) {
        Thread thread = new Thread() {
            public void run() {
                try {
                    startSignal.await();
                    dbService.findOneByID("1");
                } catch (Exception e) {
                    errors.add(e);
                } finally {
                    doneSignal.countDown();
                }
            }
        };
        thread.start();
    }
    // Create all the writer threads and start them
    for (int i = 0; i < writer; i++) {
        Thread thread = new Thread() {
            public void run() {
                try {
                    startSignal.await();
                    dbService.save(entity.builder()
                        .setID("1").setName("John").build());
                } catch (Exception e) {
                    errors.add(e);
                } finally {
                    doneSignal.countDown();
                }
            }
        };
        thread.start();
    }
    // Create all the remover threads and start them
    for (int i = 0; i < remover; i++) {
        Thread thread = new Thread() {
            public void run() {
                try {
                    startSignal.await();
                    dbService.delete("1");
                } catch (Exception e) {
                    errors.add(e);
                } finally {
                    doneSignal.countDown();
                }
            }
        };
        thread.start();
    }
    // Release the threads
    startSignal.countDown();
    // Wait until all threads did their task
    doneSignal.await();
    // If an error has been collected, print the stack trace and throws the
    // first error to make the test fail
    if (!errors.isEmpty()) {
        for (Exception e : errors) {
            e.printStackTrace();
        }
        throw errors.get(0);
    }
}

NB: If you want a given unit test to be executed by several concurrent threads, have a look to contiperf but it won't allow you to mix them as you want to achieve

Upvotes: 4

Related Questions