@PostConstruct 中的 JMockit 模拟私有方法
JMockit mock private method in @PostConstruct
上下文
在我的 class 测试中有一个 @PostConstruct
注释方法调用另一个私有方法。
@PostConstruct
public void init() {
longWork(); // private method
}
JMockit 的默认行为是在注入时执行 @Tested
class 的 @PostConstruct
方法。
If a @Tested class has a method annotated with
javax.annotations.PostConstruct, it should be executed right after
injection.
https://github.com/jmockit/jmockit1/issues/13
问题
JMockit 调用了 init()
方法,这是我不想要的。
来自线程转储:
at com.me.Worker.longWork(Worker.java:56)
at com.me.Worker.longWork.init(Worker.java:47)
...
at mockit.internal.util.MethodReflection.invoke(MethodReflection.java:96)
那个电话怎么会是mocked/removed/blocked?
尝试
我尝试模拟 init
和 longWork
方法,如下所示。然而,这会导致 NullPointerException
,因为 sut
尚未注入。
@Before
public void recordExpectationsForPostConstruct()
{
new NonStrictExpectations(sut) {{ invoke(sut, "init"); }};
}
或许您可以将 longWork 方法委托给另一个 class 并模拟这个方法。编写测试时遇到困难通常是设计缺陷的标志
您可以尝试在不使用@Tested 的情况下手动初始化要测试的class。然后,通过 setter 方法(或使用 mockit.Deencapsulation.setField() 方法)设置模拟依赖项。
您可以尝试类似的操作;
//Define your class under test without any annotation
private MyServiceImpl serviceToBeTested;
//Create mock dependencies here using @Mocked like below
@Mocked Dependency mockInstance;
@Before
public void setup() {
//Initialize your class under test here (or you can do it while declaring it also).
serviceToBeTested = new MyServiceImpl();
//Set dependencies via setter (or using mockit.Deencapsulation.setField() method)
serviceToBeTested.setMyDependency(mockInstance);
//Optionally add your expectations on mock instances which are common for all tests
new Expectations() {{
mockInstance.getName(); result = "Test Name";
...
}};
}
@Test
public void testMyMethod(@Mocked AnotherDependency anotherMock) {
//Add your expectations on mock instances specifics to this test method.
new Expectations() {{
mockInstance.getStatus(); result = "OK";
anotherMock.longWork(); result = true;
...
}};
//Set dependencies via setter or using mockit.Deencapsulation.setField() method
Deencapsulation.setField(serviceToBeTested, "myAnotherDep", anotherMock);
//Invoke the desired method to be tested
serviceToBeTested.myMethod();
//Do the verifications & assertions
new Verifications() {{
....
....
}};
}
上下文
在我的 class 测试中有一个 @PostConstruct
注释方法调用另一个私有方法。
@PostConstruct
public void init() {
longWork(); // private method
}
JMockit 的默认行为是在注入时执行 @Tested
class 的 @PostConstruct
方法。
If a @Tested class has a method annotated with javax.annotations.PostConstruct, it should be executed right after injection.
https://github.com/jmockit/jmockit1/issues/13
问题
JMockit 调用了 init()
方法,这是我不想要的。
来自线程转储:
at com.me.Worker.longWork(Worker.java:56)
at com.me.Worker.longWork.init(Worker.java:47)
...
at mockit.internal.util.MethodReflection.invoke(MethodReflection.java:96)
那个电话怎么会是mocked/removed/blocked?
尝试
我尝试模拟 init
和 longWork
方法,如下所示。然而,这会导致 NullPointerException
,因为 sut
尚未注入。
@Before
public void recordExpectationsForPostConstruct()
{
new NonStrictExpectations(sut) {{ invoke(sut, "init"); }};
}
或许您可以将 longWork 方法委托给另一个 class 并模拟这个方法。编写测试时遇到困难通常是设计缺陷的标志
您可以尝试在不使用@Tested 的情况下手动初始化要测试的class。然后,通过 setter 方法(或使用 mockit.Deencapsulation.setField() 方法)设置模拟依赖项。
您可以尝试类似的操作;
//Define your class under test without any annotation
private MyServiceImpl serviceToBeTested;
//Create mock dependencies here using @Mocked like below
@Mocked Dependency mockInstance;
@Before
public void setup() {
//Initialize your class under test here (or you can do it while declaring it also).
serviceToBeTested = new MyServiceImpl();
//Set dependencies via setter (or using mockit.Deencapsulation.setField() method)
serviceToBeTested.setMyDependency(mockInstance);
//Optionally add your expectations on mock instances which are common for all tests
new Expectations() {{
mockInstance.getName(); result = "Test Name";
...
}};
}
@Test
public void testMyMethod(@Mocked AnotherDependency anotherMock) {
//Add your expectations on mock instances specifics to this test method.
new Expectations() {{
mockInstance.getStatus(); result = "OK";
anotherMock.longWork(); result = true;
...
}};
//Set dependencies via setter or using mockit.Deencapsulation.setField() method
Deencapsulation.setField(serviceToBeTested, "myAnotherDep", anotherMock);
//Invoke the desired method to be tested
serviceToBeTested.myMethod();
//Do the verifications & assertions
new Verifications() {{
....
....
}};
}