tags:

views:

159

answers:

2

I have a JUnit test class in which I have several static final ints that can be redefined at the top of the tester code to allow some variation in the test values. I have logic in my @BeforeClass method to ensure that the developer has entered values that won't break my tests.

I would like to improve variation further by allowing these ints to be set to (sensible) random values in the @BeforeClass method if the developer sets a boolean useRandomValues = true;. I could simply remove the final keyword to allow the random values to overwrite the initialisation values, but I have final there to ensure that these values are not inadvertently changed, as some tests rely on the consistency of these values.

  1. Can I use a constructor in a JUnit test class? Eclipse starts putting red underlines everywhere if I try to make my @BeforeClass into a constructor for the test class, and making a separate constructor doesn't seem to allow assignment to these variables (even if I leave them unassigned at their declaration);

  2. Is there another way to ensure that any attempt to change these variables after the @BeforeClass method will result in a compile-time error?

  3. Can I make something final after it has been initialised?

+2  A: 

You can do this with a static constructor:

import java.util.Random;
public class StaticRandom
{
  private static final boolean useRandomValues = true;
  private static final Random r = new Random();
  private static final int value1;
  private static final int value2;
  private static final int value3;
  static
  {
    if(useRandomValues)
    {
      value1 = r.nextInt();
      value2 = r.nextInt();
      value3 = r.nextInt();
    }
    else
    {
      value1 = 0;
      value2 = 0;
      value3 = 0;
    }
  }
}
Matthew Flaschen
Perfect, that's exactly what I was after. Are static constructors as simple a concept as they appear? When will a static constructor be processed? My assumption would be that it is processed at compile time and the above code would just end up like value1 = 23140542; //Note: I just mashed the numpad here value2 = 20424040; value3 = 87618735;Then the compiler would probably replace those variables with the int literals wherever they show up in the code.
Dr. Monkey
Dr. Monkey, static blocks contain ordinary code that is processed when the class is initialized (i.e. first loaded into the JVM at runtime), not at compile time. The rules are not that complex. A couple caveats are that code is run in textual order (which means you may not be able to refer to variables in the same scope declared later), and static blocks can not throw checked excptions. For info, you can start with http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#39245 and http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html .
Matthew Flaschen
+2  A: 

You can use a static initializer:

final static boolean useRandomValues = true;

final static int valueA;
final static int valueB;
static {
    if(!useRandomValues) {
        valueA = 42;
        valueB = 1337;
    }
    else {
        Random rnd = new Random();
        valueA = rnd.nextInt(100);
        valueB = rnd.nextInt(100);
    }
}
miorel