Mocking Static Blocks in Java

后端 未结 10 1974
南方客
南方客 2021-01-30 11:00

My motto for Java is \"just because Java has static blocks, it doesn\'t mean that you should be using them.\" Jokes aside, there are a lot of tricks in Java that make testing a

相关标签:
10条回答
  • 2021-01-30 11:20

    Occasionally, I find static initilizers in classes that my code depends on. If I cannot refactor the code, I use PowerMock's @SuppressStaticInitializationFor annotation to suppress the static initializer:

    @RunWith(PowerMockRunner.class)
    @SuppressStaticInitializationFor("com.example.ClassWithStaticInit")
    public class ClassWithStaticInitTest {
    
        ClassWithStaticInit tested;
    
        @Before
        public void setUp() {
            tested = new ClassWithStaticInit();
        }
    
        @Test
        public void testSuppressStaticInitializer() {
            asserNotNull(tested);
        }
    
        // more tests...
    }
    

    Read more about suppressing unwanted behaviour.

    Disclaimer: PowerMock is an open source project developed by two colleagues of mine.

    0 讨论(0)
  • 2021-01-30 11:24

    This is going to get into more "Advanced" JMockit. It turns out, you can redefine static initialization blocks in JMockit by creating a public void $clinit() method. So, instead of making this change

    public class ClassWithStaticInit {
      static {
        staticInit();
      }
    
      private static void staticInit() {
        System.out.println("static initialized.");
      }
    }
    

    we might as well leave ClassWithStaticInit as is and do the following in the MockClassWithStaticInit:

    public static class MockClassWithStaticInit {
      public void $clinit() {
      }
    }
    

    This will in fact allow us to not make any changes in the existing classes.

    0 讨论(0)
  • 2021-01-30 11:25

    You could write your test code in Groovy and easily mock the static method using metaprogramming.

    Math.metaClass.'static'.max = { int a, int b -> 
        a + b
    }
    
    Math.max 1, 2
    

    If you can't use Groovy, you will really need to refactoring the code (maybe to inject something like a initializator).

    Kind Regards

    0 讨论(0)
  • 2021-01-30 11:27

    Not really an answer, but just wondering - isn't there any way to "reverse" the call to Mockit.redefineMethods?
    If no such explicit method exists, shouldn't executing it again in the following fashion do the trick?

    Mockit.redefineMethods(ClassWithStaticInit.class, ClassWithStaticInit.class);
    

    If such a method exists, you could execute it in the class' @AfterClass method, and test ClassWithStaticInitTest with the "original" static initializer block, as if nothing has changed, from the same JVM.

    This is just a hunch though, so I may be missing something.

    0 讨论(0)
提交回复
热议问题