The Java Explorer

Tips and insights on Java

  • Subscribe

  • If you find this blog useful, please enter your email address to subscribe and receive notifications of new posts by email.

    Join 37 other followers

Posts Tagged ‘test’

A utility for multithreaded unit tests

Posted by Eyal Schneider on July 13, 2010

Classes designed to run in a multithreaded environment are difficult to test. In a standard unit test, the test space may be already huge, since we try to cover all combinations of the object’s state and legal operations on that state. For a class designed to run in a multithreaded environment, the test space increases dramatically, due to the possible interleaving of the operations performed by the different threads on the object.

Beside the theoretic challenge, we have a practical one, that arises when simulating multiple caller threads in the test class, and trying to perform assertions in these threads. This can be demonstrated by the following numeric counter use case.  Suppose that we want to implement a thread safe counter. We will provide two implementations, so we start by defining the counter interface, consisting of a single atomic operation:


public interface Counter {
    public int incrementAndGet();
}

Following are two implementations. The first works fine only for a single threaded scenario:


public class DumbCounter implements Counter {
    private int counter;
    @Override
    public int incrementAndGet() {
        return ++counter;
    }
}

The second one is based on AtomicInteger, so it is completely thread safe:

public class AtomicIntCounter implements Counter {
    private AtomicInteger atomicInt = new AtomicInteger();
    @Override
    public int incrementAndGet() {
        return atomicInt.incrementAndGet();
    }
}

Now we want to test these implementations using JUnit. The following test simulates 5 threads operating on the same counter. Each thread tries to increment the counter 100000 times, so we expect each thread to see strictly increasing values of the counter:

 import static org.junit.Assert.assertTrue;

import java.util.concurrent.CountDownLatch;

import org.junit.Before;
import org.junit.Test;
public class TestCounters {
    private static final int THREADS_COUNT = 5;
    private Counter counter;

    @Before
    public void resetCounter() {
        counter = new DumbCounter();
    }

    @Test
    public void test() throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(THREADS_COUNT);
        for(int i = 0;i < THREADS_COUNT; i++) {
            new Thread(new Runnable(){

                @Override
                public void run() {
                    try{
                        int last = counter.incrementAndGet();
                        for (int i = 0; i < 1000000; i++) {
                            int value = counter.incrementAndGet();
                            assertTrue (value > last);
                            last = value;
                        }
                    } finally {
                        latch.countDown();
                    }
                }
            }).start();
        }

        latch.await();
    }

}

The CountDownLatch is used for waiting for all threads to terminate, before leaving the test method. The method resetCounter() is used for initializing the counter before any test method is being executed. It also chooses the particular implementation we want to test. In this case we test the non-thread-safe DumbCounter, so we expect to see the test fail. However, when we run the test we observe a strange behavior:  JUnit reports that the test passed successfully, but we see the following error messages printed to the error stream by each one of the 5 threads:

Exception in thread “Thread-{N}” java.lang.AssertionError:
at org.junit.Assert.fail(Assert.java:71)
at org.junit.Assert.assertTrue(Assert.java:34)
at org.junit.Assert.assertTrue(Assert.java:43)
at jnunit.TestCounters$1.run(TestCounters.java:31)
at java.lang.Thread.run(Thread.java:619)

The reason for this behavior is the usage of assertions outside of JUnit’s main thread. JUnit detects assertion failures by catching exceptions of type AssertionError thrown in its main thread. The framework is completely unaware of assertion errors being thrown in new threads spawned by the test methods. Consequently, these exceptions simply terminate the threads where they are thrown, and activate the default uncaught exception handler, which prints their details to the error stream. The main thread detects no errors, so it reports success.

In order to solve this situation, we need some asynchronous test runner, that delegates any unchecked exceptions to the main thread. Here is a possible solution : 


public class AsynchTester{
    private Thread thread;
    private volatile Error error;
    private volatile RuntimeException runtimeExc;

    public AsynchTester(final Runnable runnable) {
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    runnable.run();
                } catch (Error e) {
                    error = e;
                } catch (RuntimeException e) {
                    runtimeExc = e;
                }
            }
        });
    }

    public void start() {
        thread.start();
    }

    public void test() throws InterruptedException {
        thread.join();
        if (error != null)
            throw error;
        if (runtimeExc != null)
            throw runtimeExc;
    }
}

The constructor receives the task to be executed, and start() triggers the asynchronous execution. The method test() is used for waiting the task termination, and throwing unchecked exceptions if needed. Any RuntimeException or Error thrown by the test thread will be re-thrown by the test() method, in order to reflect the actual termination status of the inner thread.

Now we can re-write the test() method of our test class as follows:

@Test
public void test() throws InterruptedException {
    AsynchTester[] testers = new AsynchTester[THREADS_COUNT];
    for(int i = 0;i < THREADS_COUNT; i++) {
        testers[i] = new AsynchTester(new Runnable() {

            @Override
            public void run() {
                int last = counter.incrementAndGet();
                for (int i = 0; i < 1000000; i++) {
                    int value = counter.incrementAndGet();
                    assertTrue (value > last);
                    last = value;
                }
            }
        });
        testers[i].start();
    }

    for(AsynchTester tester : testers)
        tester.test();
}

The method structure is very similar to the original one, and it’s quite easy to synchronize the threads termination now. When testing DumbCounter using this code, we finally get the right behavior: the test fails, and points us to the position in code where the assertion failed.

It is important to note that the solution presented here addresses only one aspect of multithreaded tests, and I chose it because it is both easy to implement and uses a nice technique. However, there are some available test frameworks on the web, suitable for concurrent tests, that cover other aspects of the problem. See for example the GroboUtils JUnit extension, and also ConTest, which uses an interesting approach for increasing the coverage of multithreaded tests.

Posted in java, Testing | Tagged: , , , , , , , | 3 Comments »

Java Quiz

Posted by Eyal Schneider on September 17, 2009

This time I posted a 20 questions quiz, developed for testing general Java skills.
Most of the questions address fundamental topics in Java(5), but the test is not a trivial one.  The right answers plus their explanations can be found on the bottom. You are welcome to add your comments.

Enjoy, and good luck!

Question 1

public class CrazyCount {
    private static volatile int count = 0;

    public static void main(String[] args) {
        for(int i=0;i<1000;i++)
            new Thread(new Runnable(){
                public void run() {
	           count++;
                }
            }).start();

        //.....
    }
}

What will be the value of count after all 1000 threads finish their work?

(a) Garbage, because the writes are not synchronized
(b) A value between 1 and 1000
(c) Exactly 1000
(d) At least 1000
Answer

Question 2

Consider the following multi threaded producer/consumer model:

 public class ProducerConsumer {
    private Job currentJob = null;

    public synchronized void addJob(Job job) throws InterruptedException{
        while (currentJob!=null)
            this.wait();
        currentJob=job;
    }

    public synchronized Job consumeJob(){
        Job res = currentJob;
        res.process();
        currentJob=null;
        this.notify();
        return res;
    }
}

Which of the following is correct?

(a) addJob will wait till the current job is executed, but consumeJob will never block.
(b) Jobs will be executed in the exact order in which they are added with addJob.
(c) This code may not work because of deadlocks
(d) ‘while’ in addJob can be replaced by ‘if’, without changing the behavior.
Answer

Question 3

Consider the following Singleton design pattern implementation:

public class ConnectionsMgr {
    private static ConnectionsMgr instance = null;

    public static ConnectionsMgr getInstance(){
        if (instance==null){
	    synchronized(ConnectionsMgr.class){
		if (instance==null)
		    instance = new ConnectionsMgr();
	    }
    	}
	return instance;
    }

    //...
}

Why is this implementation problematic?

(a) An uninitialized ConnectionsMgr object may be returned
(b) Synchronizing on ConnectionsMgr.class is not allowed
(c) The instance may be created more than once
Answer

Question 4

Which of the following statements regarding the final reserved word is correct?

(a) A final method can not be overriden by subclasses, and a final class can not be subclassed
(b) A final data member must be given a value in its declaration line
(c) A local variable declared as final can still be mutated using setter methods
(d) (a) and (c) are correct
Answer

Question 5

public static void main(String[] args) {
    try{
	String s = null;
	s=s.substring(10);
    }
    catch(Exception e){
	System.out.println("Caught exception!");
    }
    catch(RuntimeException e){
	System.out.println("Caught a runtime exception!");
    }
}

This code:

(a) Displays “Caught exception!” when executed
(b) Displays “Caught runtime exception!” when executed
(c) Runs without throwing an exception
(d) Does not compile
Answer

Question 6

Which of the following statements regarding exceptions is correct?

(a) IOException can be thrown without the need to declare it in the method header
(b) catch(Exception) will catch OutOfMemoryError
(c) ClassCastException can be thrown without the need to declare it in the method header
(d) (b) and (c) are correct
Answer

Question 7

Which of the following is the preferred way to stop a thread?

(a) Calling the Thread’s interrupt() method
(b) Calling interrupt() and then stop()
(c) Calling the stop() method
(d) Calling join() to wait for the thread to end
Answer

Question 8

public class Swap {
    public static void swapStrings(String x, String y){
	String temp = x;
	x=y;
	y=temp;
    }

    public static void main(String[] args) {
	String a = "1";
	String b = "2";
	swapStrings(a, b);
	System.out.println("a="+a+" ,b="+b);
    }
}

What will be the output when executing this main?

(a) An exception will be thrown
(b) “a=2 ,b=1”
(c) “a=1 ,b=2” because strings are immutable
(d) “a=1 ,b=2” because Java passes parameters by value
Answer

Question 9

public static void main(String[] args) {
    ArrayList<Point> list = new ArrayList<Point>();
    list.add(new Point(100,200));

    ArrayList<Point> listCopy = (ArrayList<Point>) list.clone();

    listCopy.get(0).setLocation(150,250);

    System.out.println(list);
    System.out.println(listCopy);
}

What will be the output of this main?

(a) [java.awt.Point[x=100,y=200]]
[java.awt.Point[x=100,y=200]]

(b) [java.awt.Point[x=150,y=250]]
[java.awt.Point[x=100,y=200]]

(c) [java.awt.Point[x=100,y=200]]
[java.awt.Point[x=150,y=250]]

(d) [java.awt.Point[x=150,y=250]]
[java.awt.Point[x=150,y=250]]
Answer

Question 10

Assume that class B extends class A.
Consider a method that is declared as follows:  public void callMe(List<A> l)

Which of the following data types can be passed as parameters to callMe(..)?
(a) List<B>
(b) ArrayList<B>
(c) ArrayList<A>
(d) All answers are correct
Answer

Question 11

Assumes that class B extends class A.

public void callMe(List<? extends A> l){
    l.add(new A());
    l.add(new B());
}

This method:

(a) Compiles, but with a warning
(b) Does not compile
(c) Runs correctly
(d) May cause ClassCastException
Answer

Question 12

What will be the output of the following code?

class Base {
    int i = 10;

    public Base(){
        System.out.println(get());
    }

    public int get(){
        return i;
    }

}
public class Derived extends Base{
    int j = 20;

    public int get(){
        return j;
    }

    public static void main(String argv[]){
        Base b = new Derived();
    }
}

(a) 0
(b) 10
(c) 20
(d) None of the above
Answer

Question 13

What will be the output of the following code?

class Base {
    protected int i = 10;

    public int get(){
        return i;
    }
}

public class Derived extends Base{
    protected int i = 20;

    public int get(){
        return i;
    }

    public static void main(String argv[])
    {
        Base b = new Derived();
        System.out.println(b.i);
        System.out.println(b.get());
    }
}

(a) 10
10

(b) 10
20

(c) 20
10

(d)
20
20
Answer

Question 14

What is the output of the following code?

String s1 = new String("Test");
String s2 = "Test";
if (s1==s2)
    System.out.println("Same");
if (s1.equals(s2))
    System.out.println("Equals");

(a) Same
(b) Equals
(c) Same
Equals
(d) No output
Answer

Question 15

What is the output of the following code?

class Parent{
    private void f(){
        System.out.println("Parent.f()");
    }

    public void g(){
        System.out.println("Parent.g()");
        f();
    }
}

public class Child extends Parent{
    public void f(){
        System.out.println("Child.f()");
    }

    public static void main(String args[]){
        Parent p = new Child();
        p.g();
    }
}

(a) Parent.g()
Child.f()
(b) Parent.g()
Parent.f()
(c) The code does not compile
(d) An exception is thrown
Answer

Question 16

Consider the following overloading scenario:

public class Overloader{
    public static void read(String s){
        System.out.println("read(String)");
    }

    public static void read(Integer i){
        System.out.println("read(Integer)");
    }

    public static void read(Object o){
        System.out.println("read(Object)");
    }

    public static void main(String args[]){
        Object s = new String("Java");
        Integer i = 10;
//      Overloader.read(s);
//      Overloader.read(i);
//      Overloader.read(null);
    }
}

What would be the output of each of the 3 read commands in comment?

(a) read(s) prints “read(String)”
read(i) prints “read(Integer)”
read(null) prints “read(Object)”

(b) read(s) prints “read(Object)”
read(i) prints “read(Integer)”
read(null) prints “read(Object)”

(c) read(s) prints “read(Object)”
read(i) prints “read(Integer)”
read(null) does not compile

(d) None of the above
Answer

Question 17

Which of the following statements is correct?

(a) A daemon thread is terminated when all non-daemon threads terminate
(b) A thread is created as a daemon thread if and only if it is created by a daemon thread
(c) Non daemon threads may keep the application from shutting down, even if the main thread is terminated.
(d) All of the above are correct
Answer

Question 18

class Parent{
    protected void x(){}
    public void y(){}
}

public class Child extends Parent{
    public void x(){}
    protected void y(){}
}

When compiling this code:
(a) It compiles successfully
(b) Compilation error – x can’t have its visibility increased
(c) Compilation error – y can not have its visibility reduced
(d) Compilation error – neither x nor y can have their visibility changed
Answer

Question 19

String s = new String("Wanna live forever!");
WeakReference<String> r1 = new WeakReference<String>(s);
SoftReference<String> r2 = new SoftReference<String>(s);
String s2 = r1.get();
s = null;

Assuming that no garbage collection took place, what is the reference strength of the string created at line #1, after these lines of code?
(a) Not referenced
(b) Weakly referenced
(c) Softly referenced
(d) Strongly referenced
Answer

Question 20

int x=0;
int y=0;
while(true){
    if ((++x==10) && (++y==10))
        return;
}

When executed, this code:
(a) Performs 10 iterations and ends
(b) Performs more than 10 iterations and ends
(c) Performs less than 10 iterations and ends
(d) Enters an infinite loop
Answer

Answers

1)  (b)
A race condition between threads may cause a a write to cancel other writes, thus multiple concurrent “incrementations” may result in a single incrementation.

2) (a)
(b) is incorrect, since there is no guarantee about the order in which waiting threads are awakened using Object.notify().
(d) is incorrect because when a producer thread is awakened, there is no guarantee that another producer thread was not awakened just before, setting the current job to another value.
Besides, Java documentation recommends always to use ‘while’ loops on wait() rather than ‘if’.

3) (a)
The line “instance=new ConnectionsMgr()” is not atomic. It results in multiple machine instructions, one of which is the reference assignment itself. Due to the Java memory model rules, this specific instruction is allowed to be reordered with respect to the other instructions. This reordering may cause the assignment to take effect before the object is initialized. Another thread calling getInstance() may therefore receive a non null reference to an uninitialized memory block.  See this article for more details.

4) (d)
An object data member or a local object variable declared as final can not change its address. However, the referenced object can be freely mutated.
(b) is not true because the member can be initialized in the constructor/s also.

5) (d)
RuntimeException derives from Exception, so the ordering of the catch blocks makes the second unreachable.

6) (c)
ClassCastException is an unchecked exception, so it does not need to be declared. IOException, however, is a checked exception, and you must either catch it or declare the method as “throws IOException”. OutOfMemoryError is a Throwable, but it derives from Error and not from Exception.

7)  (a)
Thread.stop() is a deprecated method that is not recommended for use. It stops a thread violently without guaranteeing anything about the integrity of the data manipulated by that thread. This may cause corrupt data to be viewed by other threads. Furthermore, there are some cases in which Thread.stop() will not terminate a thread.
Thread.interrupt() is preferred, but it relies on the code run by the thread to be friendly and react to the interruption.

8) (d)
Since Java passes parameters by value (not by reference!), there is no way to implement a swap method in Java. In C++ for example, it is possible, using references (&).

9) (d)
Collections such as java.util.ArrayList do not perform deep copying when cloned. Item references stay the same.

10) (c)
(a) and (b) are incorrect because if legal, they would have break the type safety. The method callMe could have added an instance of type A, and the caller now has a collection of both A’s and B’s, while it assumes that it has only elements of type B. See my previous post for more details.

11) (b)
Assume that C descends from B. The method callMe may receive as a parameter an object of type List<C>. If the additions were considered legal, this would result in a list defined as List<C> containing instances of super classes such as B and A. That breaks the generics type safety, since it will not protect the collection from an unexpected ClassCastException. See my previous post for more details.

12) (a)
Overriding methods that are called directly/indirectly by the superclass’ constructor should be done with care. If the overriden method uses data members belonging to the subclass, then they are still not initialized at that point! In this example, the data member is of type int, so the default initialization will give it a value 0.
For more explanations and a workaround for this problem, see posts 86 and 86b of the Java Specialists’ Newsletter.

13) (b)
Methods are invoked virtually – the exact method to be executed is determined at runtime according to the actual class of the object on which it was called. Data members, however, do not really override each other. Each class has its member i, and the one to be retrieved is determines at compile time, according to the declared class of the reference (in this case Base).

14) (b)
Using new String(…) forces Java to actually create a new instance of a string. Strings defined as literals (e.g. String x=”hello”), however, will always be represented by the same object reference at runtime.

15) (b)

16) (c)
The method signature to be invoked is determined at compile time. Therefore, it depends on the declared type and not the runtime type of the argument/s.
Regarding the null parameter – the compiler can not determine which signature is the correct one, since all the three reads are legitimate.

17) (d)

18) (c)
Reducing visibility of methods when overriding is not permitted.

19) (d)
s2 still hard-references the string.

20) (b)
Tricky thing… The Java language specification specifies that the second operand of && is never evaluated when the first operand evaluates to false (See this section). Consequently, only when x reaches 10 y will become 1. Later, x will overflow and reach 10 again, and so on; until both counters reach 10 and the loop will stop.

Posted in java, Language | Tagged: , , | 10 Comments »