使用 PowerMock 防止静态初始化
Use PowerMock to prevent static initialization
所以我的 class 测试中有一个静态变量。我试图用 Powermockito 模拟它,但出现错误。
public class ClassUnderTest{
private static EntityManager em = AppEntityManager.createEntityManager();
public static String methodUnderTest(){
// this method dosent use EntityManager em
}
}
我的测试class是这样的:
@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()
有什么方法可以防止 EntityManager em
?
的静态初始化
通过实践更好的设计原则。
Can you tell me where I am going wrong?
与该静态依赖项的紧密耦合现在使您的代码难以测试。
使它成为通过构造函数注入的显式依赖项。
public class ClassUnderTest{
private EntityManager em;
public ClassUnderTest(EntityManager em) {
this.em = em;
}
public String methodUnderTest(){
// this method dosent use EntityManager em
}
}
现在在测试时您可以简单地传递一个 null EntityManager
,因为测试不需要它。
使用 PowerMockito.when
而不是 Mockito.when
。
并删除 ClassUnderTest
的 mockStatic
。
所以:
PowerMockito.mockStatic(AppEntityManager.class);
PowerMockito.when(AppEntityManager.createEntityManager()).thenReturn(emMock);
这段代码对我有用
@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);
}
}
一些要点
- 因为 EntityManager 不是
@Aurowired
,所以不需要 @InjectMocks
。
- 既然要调用
ClassUnderTest::methodUnderTest
下的代码,就不要在@PrepareForTest
下使用ClassUnderTest
- 不要
PowerMockito.mockStatic(ClassUnderTest.class);
说了这么多。你应该认真考虑重构你的代码以最小化(如果可能的话消除)所有静态方法和字段。
正如许多其他已经提到的,你真的不应该使用静态依赖,因为它会导致那种可怕的可测试设计。
但是,如果您无法更改被测代码,您可以通过反射注入 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 "";
}
}
这样您还可以关闭潘多拉魔盒又名 PowerMock 并继续进行基本的单元测试和模拟。
所以我的 class 测试中有一个静态变量。我试图用 Powermockito 模拟它,但出现错误。
public class ClassUnderTest{
private static EntityManager em = AppEntityManager.createEntityManager();
public static String methodUnderTest(){
// this method dosent use EntityManager em
}
}
我的测试class是这样的:
@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()
有什么方法可以防止 EntityManager em
?
通过实践更好的设计原则。
Can you tell me where I am going wrong?
与该静态依赖项的紧密耦合现在使您的代码难以测试。
使它成为通过构造函数注入的显式依赖项。
public class ClassUnderTest{
private EntityManager em;
public ClassUnderTest(EntityManager em) {
this.em = em;
}
public String methodUnderTest(){
// this method dosent use EntityManager em
}
}
现在在测试时您可以简单地传递一个 null EntityManager
,因为测试不需要它。
使用 PowerMockito.when
而不是 Mockito.when
。
并删除 ClassUnderTest
的 mockStatic
。
所以:
PowerMockito.mockStatic(AppEntityManager.class);
PowerMockito.when(AppEntityManager.createEntityManager()).thenReturn(emMock);
这段代码对我有用
@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);
}
}
一些要点
- 因为 EntityManager 不是
@Aurowired
,所以不需要@InjectMocks
。 - 既然要调用
ClassUnderTest::methodUnderTest
下的代码,就不要在@PrepareForTest
下使用ClassUnderTest - 不要
PowerMockito.mockStatic(ClassUnderTest.class);
说了这么多。你应该认真考虑重构你的代码以最小化(如果可能的话消除)所有静态方法和字段。
正如许多其他已经提到的,你真的不应该使用静态依赖,因为它会导致那种可怕的可测试设计。
但是,如果您无法更改被测代码,您可以通过反射注入 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 "";
}
}
这样您还可以关闭潘多拉魔盒又名 PowerMock 并继续进行基本的单元测试和模拟。