How to force the static block running in each test

2019-04-24 09:39发布

问题:

I found static block is running only once when I execute multiple JUnit tests. How can I force it to run for each test method? I am using latest JUnit 4.8.2

Also, according to xUnit design principle, every method should be totally independent on others. Why static block only be executed once?

@Test TestMethod1 () {
       Accounts ac = new Accounts();
       ac.method1(); //kill the thread inside
}

@Test TestMethod2 () {
       Accounts ac = new Accounts();
       ac.method2(); // the thread is no longer available!!
}

class Accounts {
   static {
       // initalize one thread to monitor something
   }
}

This even happens when TestMethod1 and TestMethod2 are in the different Test Classes.

回答1:

static blocks are only executed on class loading because that is what they are: class initializers. To have a static block run multiple times would require you to unload the class (not an easy thing to do...).

If you need to use static blocks, you can come up with ways to test them. Why not unwrap the block into a public (static) method? All you have to do in that world is test the method:

 static {
      staticInitMethod();
 }

 public static void staticInitMethod(){
      //insert initialization code here
 }

you also might be able to get away with just an ordinary initializer

 {//not static
      //insert initialization code here
 }

Although, the truth is most code doesn't need to use initializers like this at all.

Edit: Turns out Oracle likes the static method approach http://download.oracle.com/javase/tutorial/java/javaOO/initial.html



回答2:

Why static block only be executed once?

Because that is the whole point of static initializer blocks!

Or to put it another way, if you want some initialization code to execute multiple times, put it in a regular constructor or method, or (in a tiny number of cases) a non-static initializer block.


In the context of JUnit, the normal way to implement test startup and shutdown code using setUp() and tearDown() methods.


If you are trying to unit test the execution of static initialization in your own code, you are in for a rough road I think. But then, unit testing of code with static state (e.g. singletons) is always difficult ... and that's one of the reasons that people think that static state is a bad idea.

  • Consider using a Dependency Injection (aka Inversion of Control) framework instead of singletons.

  • Alternatively, consider modifying your singletons / static initialization code to make it easier to test. For instance, add a static method that allows a test to re-execute the initialization. (And before you say that this breaks the singleton pattern: yes I know. You need to choose between design / implementation "purity" and ease of testing.)



回答3:

Is the static code for the tests for the class being tested?

If the code is static so the tests can share, then you need to move the code into its own class. Then either have the test class constructor instantiate a static instance or create a test suite that does the same thing.

If you want each test to stand alone, then move what you are doing in your static block into the setup()/teardown() methods, it's what they are there for.



回答4:

Static block is executed only once when first time class is loaded into JVM. Junit provide @Before annotation which is basically used for required initialization fro test case. This can be used for executing static blocks of class. for example I have following class Car

    public class Car implements Vehicle{

        private String type = "lmv";    
        static {            
            VehicleFactoryWithoutRefl.getInstance().registerVehicle("car", new Car());
        }
        @Override
        public void moveForward() {
        }

        @Override
        public String getType() {
            return type;
        }

        @Override
        public Vehicle createVehicle() {
            return new Car();
        }



    }

and I want to execute static block of this class in Junit before creating the car instance. I have to load this class in setUp() using class.forName("package.ClassName") Junit code.

  public class TestFactory {

        @Before
        public void setUp() {
            try {
                Class.forName("com.cg.dp.factory.Car");
            } catch (ClassNotFoundException e) {
                //e.printStackTrace();
            }
        }

        @Test
        //@Ignore
        public void testFactoryInstanceWithoutRefl() {
            Vehicle v1 = VehicleFactoryWithoutRefl.getInstance().newVehicle("car");
            assertTrue(v1 instanceof Car);
        }
    }


回答5:

Um... make it non-static? You can have instance initializer blocks too (same as static blocks, just without the static keyword). But test setup code should actually go into an explicit setUp() or @Before method.