从测试方法

时间:2016-01-04 23:41:51

标签: java mockito classloader junit4 powermockito

我正在使用带有Mockito的PowerMock 1.6的Junit 4.12。我还使用了here所描述的PowerMockRule库。我正在尝试按照this SO Thread中的描述为我的所有测试用例执行一次初始化代码。它执行初始化代码恰好一次,如果我在test方法中做ServiceInitializer.INSTANCE它会返回我的新对象。我无法理解这种行为。有谁知道为什么会这样?如果我在没有PowerMockRule库的情况下执行我的代码并使用PowerMockRunner运行我的测试,那么它工作正常但在这种情况下我的ClassRule没有被执行。

    public class ServiceInitializer extends ExternalResource {
      public static final TestRule INSTANCE = new ServiceInitializer();
      private final AtomicBoolean started = new AtomicBoolean();

      @Override protected void before() throws Throwable {
        if (!started.compareAndSet(false, true)) {
          return;
        }
        // Initialization code goes here
        System.out.println("ServiceInitializationHelper:"+this); //Print Address @3702c2f1
      }

      @Override protected void after() {
      }
    }




    class BaseTest{
            @Rule
            public PowerMockRule powerMockRule = new PowerMockRule();

              @ClassRule
              public static final TestRule serviceInitializer = ServiceInitializer.INSTANCE;

              @Before
              public final void preTest() {
                // some code
              }

              @After
              public final void postTest() {
                //some code
              }
    }


@PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
      @Test
      public void testMethodA_1(){
            System.out.println(ServiceInitializer.INSTANCE);//Print Address @54d41c2b
      }
}

更新

我打印了类的类加载器,结果是第一个print语句,classloder是sun.misc.Launcher$AppClassLoader,而第二个print语句是classloder org.powermock.core.classloader.MockClassLoader。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:3)

你没有单身人士。您有一个静态INSTANCE变量。请记住,每个类加载器都可以存在其中一个。

而是创建一个ServiceInitializer的枚举,就像这样

public enum ServiceInitializer {
  INSTANCE;

  // rest of class goes here
}

依靠JVM的语言合同来确保单身人士。

或者,更好的是,编写代码来处理可能存在多个ServiceInitializer的情况,但只是您的程序只使用一个实例。这是理想的选择,如果需要,您可以在真正的ServiceInitializer和模拟之间切换。

答案 1 :(得分:1)

埃德温是对的;这是PowerMock为每个测试创建一个新的ClassLoader的问题。我强烈建议您重构代码,以便在没有PoeerMock的情况下进行测试并切换到Mockito。

这些书可能会有所帮助

同时,您可以从基类中引用ServiceInitializer

    public class ServiceInitializer extends ExternalResource {
      public static final ServiceInitializer INSTANCE = new ServiceInitializer();
      private final AtomicBoolean started = new AtomicBoolean();

      @Override protected void before() throws Throwable {
        if (!started.compareAndSet(false, true)) {
          return;
        }
        // Initialization code goes here
        System.out.println("ServiceInitializationHelper:"+this);
      }

      @Override protected void after() {
      }
    }




    class BaseTest{
            @Rule
            public PowerMockRule powerMockRule = new PowerMockRule();

              @ClassRule
              public static final ServiceInitializer serviceInitializer = ServiceInitializer.INSTANCE;

              @Before
              public final void preTest() {
                // some code
              }

              @After
              public final void postTest() {
                //some code
              }
    }


@PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
      @Test
      public void testMethodA_1(){
            System.out.println(serviceInitializer);
      }
}

答案 2 :(得分:0)

好吧,我终于找到了解决这个问题的方法。正如我的问题所解释的那样,我的课程被两个不同的类加载器加载,从而给我带来了麻烦。为了解决我的问题,我使用@PowerMockIgnore注释来推迟加载,如下所示:

@PowerMockIgnore({"com.mypackage.*"})
class BaseTest{
      // Stuff goes here
}

此注释告诉PowerMock将带有提供给value()的名称的类加载到系统类加载器。您可以从here了解此注释。