使用PowerMock来防止静态初始化

时间:2018-02-22 14:56:33

标签: java junit mockito powermock powermockito

所以我的班级中有一个静态变量。我试图用Powermockito来嘲笑它,但我收到了错误。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<div>
    <div class="img-wrapper"></div>
</div>

我的测试类是这样的:

public class ClassUnderTest{
  private static EntityManager em = AppEntityManager.createEntityManager();
   public static String methodUnderTest(){
       // this method dosent use EntityManager em
   }
}

错误是

@RunWith(PowerMockRunner.class)
@PrepareForTest({ AppEntityManager.class, ClassUnderTest.class })

public class ClassUnderTestTest {
 @Mock
 private EntityManager emMock;
 @InjectMocks
 private ClassUnderTest feMock;

 static ClassUnderTest fe = new ClassUnderTest();

 @Before
 public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
 }

 @Test
 public void test() {
     PowerMockito.mockStatic(ClassUnderTest.class);
    PowerMockito.mockStatic(AppEntityManager.class);
    Mockito.when(AppEntityManager.createEntityManager()).thenReturn(emMock);


        String s = ClassUnderTest.methodUnderTest(myParams);
        // assertEquals(prams[i][1], s);
        System.out.println(s);

  }

}
你能告诉我哪里出错吗? 我只想测试Feb 22, 2018 9:37:31 AM oracle.jdbc.driver.OracleDriver registerMBeans SEVERE: Error while registering Oracle JDBC Diagnosability MBean. java.lang.LinkageError: loader constraint violation: loader (instance of org/powermock/core/classloader/MockClassLoader) previously initiated loading for a different type with name "javax/management/MBeanServer" ,那么有什么方法可以阻止methodUnderTest()的静态初始化?

4 个答案:

答案 0 :(得分:1)

通过实践更好的设计原则。

  

你能告诉我哪里出错了吗?

紧密耦合到该静态依赖项现在使您的代码难以测试。

使其成为通过构造函数注入的显式依赖项。

public class ClassUnderTest{
    private EntityManager em;

    public ClassUnderTest(EntityManager em) {
        this.em = em;
    }

    public String methodUnderTest(){
       // this method dosent use EntityManager em
   }
}

现在测试时,您可以简单地传递空EntityManager,因为测试中不需要它。

答案 1 :(得分:1)

此代码适用于我

@RunWith(PowerMockRunner.class)
@PrepareForTest({ AppEntityManager.class}) 
public class ClassUnderTestTest {

  @Mock
  private EntityManager emMock;

  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void test() {
    PowerMockito.mockStatic(AppEntityManager.class);
    Mockito.when(AppEntityManager.createEntityManager()).thenReturn(emMock);

    String s = ClassUnderTest.methodUnderTest(myParams);
    // assertEquals(prams[i][1], s);
  }

}

一些要点

  1. 由于EntityManager不是@Aurowired,因此不需要@InjectMocks
  2. 由于您希望调用ClassUnderTest::methodUnderTest下的代码,因此请勿在{{1​​}}中使用ClassUnderTest
  3. 不要@PrepareForTest
  4. 说完所有这些。您应该认真考虑重构代码以最小化(如果可能消除)所有静态方法和字段。

答案 2 :(得分:0)

使用PowerMockito.when代替Mockito.when

并移除mockStatic的{​​{1}}。

所以:

ClassUnderTest

答案 3 :(得分:0)

正如许多其他已经提到的那样,你真的不应该使用静态依赖,因为它会导致那种可怕的可测试设计。

但是,如果您无法更改测试中的代码,则可以通过反射注入EntityManager:

public class ClassUnderTestTest {

    private ClassUnderTest classUnderTest;

    @BeforeEach
    public void setUp() throws Exception {
        final Field entityManagerField;

        classUnderTest = new ClassUnderTest();

        //Use getDeclaredField(...) since field is private
        entityManagerField = classUnderTest.getClass()
                                           .getDeclaredField("em");
        //Set accessible since field is private
        entityManagerField.setAccessible(true);
        entityManagerField.set(classUnderTest, 
                               Mockito.mock(EntityManager.class));
    }

    @Test
    public void test() {
        String s = classUnderTest.methodUnderTest();
        // assertEquals(prams[i][1], s);
        System.out.println(s);
    }
}

class ClassUnderTest{
    private static EntityManager em;
    public String methodUnderTest(){
        // this method dosent use EntityManager em
        // but solution don´t care
        return "";
    }
}

这样你也可以关闭Pandora's Box又名PowerMock并继续进行基本的UnitTesting和嘲笑。