when use @Mocked on Util class, static field may not initialized correctly and would leads the unit test in other classes to fail #336

Closed
haoyuche opened this Issue Sep 16, 2016 · 2 comments

Projects

None yet

2 participants

@haoyuche
haoyuche commented Sep 16, 2016 edited

Please provide the following information:

  • Version of JMockit that was used:
    1.27
  • Description of the problem or enhancement request:
    I have create 3 classes. One Utils class which only contains static field and static method. Two classes the first only calls the static method in Utils class, the second one only call the static field in the Utils class. The situation is that the static field call some static method inside the Utils class to get initialized(some methods like getInstance() to get an instance).
    The I run the UseUtils1Test and UseUtils2Test, the test in UseUtils2Test fails cause the static field in Utils class is not initialized correctly (is an empty list when @Mocked called in UseUtils1Test). Run them independently would pass all the test.

Here is the code:

public class Utils {
    protected static final List<String> field1 = getField();
    protected static List<String> getField() {
        List<String> res = new ArrayList<>();
        res.add("Field");
        return res;
    }
    protected static int getInt() {
        return 1;
    }
}

public class UseUtils1 {
    public int method1() {
        return Utils.getInt();
    }
}

public class UseUtils2 {
    public List<String> method2() {
        return Utils.field1;
    }
}

public class UseUtils1Test {
    @Mocked Utils utils;

    UseUtils1 useUtils1 = new UseUtils1();

    @Test
    public void testMethod1() {
        new Expectations() {{
            Utils.getInt(); result = 1; times = 1;
        }};
        assertEquals(1, useUtils1.method1());
    }

}

public class UseUtils2Test {
    UseUtils2 useUtils2 = new UseUtils2();

    @Test
    public void testMethod2() {
        List<String> res = useUtils2.method2();
        assertEquals(1, res.size());
        assertEquals("Field", res.get(0));
    }
}

The question1 is: When call @Mocked Utils utils; in UseUtils1Test, why the Utils.field1 initialized to a empty list. When field1 is a String instead of a list, the getField() would always work when return a String instead of a List.
The question2 is: @Mocked Utils utils; is used in UseUtils1Test class, when the test ends in UseUtils1Test, why the class-level static field still exits in JVM, and cause tests to fail in UseUtils2Test, is that supposed to be? Considering I am calling the real Utils class not the Mocked one in UseUtils2Test.

@haoyuche haoyuche changed the title from when use @Mocked on Util class, static field may not initialized correctly in and would leads the unit test in other classes to fail to when use @Mocked on Util class, static field may not initialized correctly and would leads the unit test in other classes to fail Sep 16, 2016
@rliesenfeld
Member

I believe you can find answers to these questions in the API documentation, or in the Tutorial.

@rliesenfeld rliesenfeld self-assigned this Sep 17, 2016
@rliesenfeld
Member

On closer inspection, I found an opportunity to improve the way classes get initialized right before being mocked.

@rliesenfeld rliesenfeld reopened this Sep 17, 2016
@rliesenfeld rliesenfeld added a commit that closed this issue Sep 17, 2016
@rliesenfeld rliesenfeld Improves the automatic static initialization of a class that is about…
… to be mocked, avoiding static fields left uninitialized due to mocked methods that get called from the static initializer; closes #336.
bdc15dd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment