1

I'm trying to write a JUnit test. My problem is that my threads can't see the object I have created in the sequential bit of code (code before starting the threads).

public class MyTest implements Runnable {

    private MyClass mc;

    /**
     * @throws InterruptedException
     */
    @Test
    public void parallelTest() throws InterruptedException {
        this.mc = new MyClass();
        Thread thread1 = new Thread(new MyTest());
        Thread thread2 = new Thread(new MyTest());
        thread1.join();
        thread2.join();
        thread1.start();
        thread2.start();
        // TODO the test
    }

    public void run() {
       if(mc != null) {
          System.out.println("ph not null");
       } else {
          System.out.println("ph null"); // THIS CODE GETS EXECUTED
       }
       // some code
    }
}

See the comment in the run method above. My object is null but I want both threads to be able to access the MyClass object. How come they see null? I tried using a constructor but I think the interface prevented me from passing a parameter to the constructor.

Many thanks.

6
  • Why are you joining before starting?
    – Jeffrey
    Commented Jul 20, 2013 at 16:48
  • 2
    I'm trying to write a JUnit test for my unit test: This is going too far ;-)
    – JB Nizet
    Commented Jul 20, 2013 at 16:49
  • Your problem is deeper: you do not know what an object and what new does - and this is quite a problem for a Java programmer. If I were you, I would stay away from threads and testing and for some time - just stick to some basic stuff (writing classes, making instances and objects). If you manage to fix your code (by writing this instead of new MyTest()) in the two lines instantiating threads, you will run into deeper problems, as writing correct programs using multiple threads, and testing them, is much, much, much, much harder than that.
    – fdreger
    Commented Jul 20, 2013 at 16:51
  • What are your reasons for testing a unit test and for using threads to do so? Commented Jul 20, 2013 at 16:56
  • @JB Nizet: LOL! Question edited.
    – ale
    Commented Jul 20, 2013 at 17:38

3 Answers 3

5

Each runnable instance is created using new MyTest(). And the MyTest class doesn't have any constructor initializing the field private MyClass mc;. So it has its default value: null.

Each object has its own instance fields. That's a basic principle of OO.

0

You initialize the .mc filed of this but then you create two new instances of MyTest (in which .mc is not initialized, that is: it is null) and pass these instances to your threads.

The solution is therefore quite simple: pass this to the threads.

[EDIT]

Also, I had to switch the order of the .start() and the .join() calls - waiting for a thread to finish (i.e., join) is meaningful only if the thread has been previously started.

package p1;

import org.junit.Test;

public class MyTest implements Runnable {

  private MyClass mc;

  /**
   * @throws InterruptedException
   */
  @Test
  public void parallelTest() throws InterruptedException {
      this.mc = new MyClass();
      Thread thread1 = new Thread(this);
      Thread thread2 = new Thread(this);
      thread1.start();
      thread2.start();
      thread1.join();
      thread2.join();
  }

  public void run() {
     if(mc != null) {
        System.out.println("ph not null");
     } else {
        System.out.println("ph null"); // THIS CODE GETS EXECUTED
     }
     // some code
  }
}

When I run it I get this output:

ph not null
ph not null
4
  • Tried this but then I get Test class should have exactly one public zero-argument constructor
    – ale
    Commented Jul 20, 2013 at 17:56
  • I just tried running the code and got "ph not null" as output. I am updating the answer again with exactly the same code that works for me .
    – Itay Maman
    Commented Jul 20, 2013 at 19:18
  • Which version for JUnit are you using (if it matters?). I found a solution (see the one I posted) but your solution would be simpler if I could get it working. I'm using JUnit 4.
    – ale
    Commented Jul 20, 2013 at 19:28
  • Yes. With this solution you cannot have a constructor that takes argument. You're adding a constructor that takes a parameter made JUnit produce the Test class should have exactly one public zero-argument constructor message. Once you go back to no construcotr or a single zero-arg constructor JUnit will stop complaining.
    – Itay Maman
    Commented Jul 20, 2013 at 19:33
0

I worked it out :). I'll give some +1s because there were some further problems I had:

  1. @Jeffrey: Yes, start and join were the wrong way round
  2. @JB Nizet: Thanks.. I had a crazy typo in my question (edited question)

@Itay Maman had the same idea as me but it didn't work - JUnit wouldn't let me pass a parameter into its constructor.

Solution was not to use a constructor but use @BeforeClass annotation and an init method to instantiate a MyClass.

public class MyTest implements Runnable {

    private static MyClass mc;

    @BeforeClass
    public static void init() {
        mc = new MyClass();
    }

    @Test
    public void parallelTest() throws InterruptedException {
        Thread thread1 = new Thread(new MyTest());
        Thread thread2 = new Thread(new MyTest());
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        // my assertion about mc object goes here
    }

    public void run() {
        // code to test
    }
}

This unit test still doesn't test the code perfectly because the execution path is non-deterministic so it could sometimes pass and sometimes fail. Perhaps I will add some finer grain tests too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.