使用 Mockit 做一些类似 JMockit 的 MockUp
Do with Mockit something like MockUp from JMockit
我想用 JMockit 做一些类似于 'MockUp' 的事情,但是使用 Mockito。
我想控制扩展 class 我想测试的 class 方法的行为。
但我有一个问题,那就是该方法是私有的,所以我认为我不能使用 Mockito,需要使用 PowerMock。
问题
Class A extends B{...}
Class B {
private Header generateHeaderForServiceCall(c,d,f,g,h,j){...}
}
在我的 Class ATest{ 在 @Before 中,我想模拟 generateHeaderForServiceCall(.....) 只为 return 创建一个默认的 Header对我来说。 }
因此,使用 JMockit 就像:
new MockUp<Controller>() {
@Mock
private Header generateHeaderForServiceCall(...) {
return defaultHeader;
}
};
我会更好地说明我的上下文:
public class B {
private Header generateHeaderForServiceCall(Input A, Input B, Input c, Input D) throws ServiceException {
......
//do stuff
return header}
}
public class A extends B {
@Override
public Response process(Request request) throws SOAException {
//do stuff
try {
method_i_want_to_test(Input A, Input B);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
protected Dossier method_i_want_to_test(Input A, Input B) throws
SOAException {
... //do stuff
**Header** **header** = generateHeaderForServiceCall(Input A, Input
B,Input c, Input D);**
// **doLogic** with header returned and return the result
}
}
我想做什么:
private A aTest;
@Before
public void setUp() throws Exception {
PowerMockito.mock(aTest);
PowerMockito.doReturn(defaultHeader).when(aTest,"generateHeaderForServiceCall", params);
}
因此,当我转到 method_i_want_to_test 并调用 generateHeaderForServiceCall 时,我只想获得默认值 header,而忽略方法的输入和逻辑。我想模拟这个方法,但是它 private/protected.
那么,我可以使用 Mockito 吗?
我需要使用 PowerMock 吗?
我可以同时使用 Mockito 和 PowerMockit 吗?
------------------------------------ 更新----------------------------
所以,我的 classA,我想测试的是:
package mypackage;
import package.ClassB;
@Service
public class ClassA extends ClassB implements Xinterface {
@Inject
public ClassA(InputA inputA, InputB inputB,InputC inputC, InputD inputD) {
...
}
@Override
public ClassAResponse process(ClassARequest request) throws SOAException {
ClassAResponse response = initResponse(inputA, request, new ClassAResponse());
ClassAInput input = request.getInput();
ClassAOutput output = new ClassAOutput();
response.setOutput(output);
try {
/* */
method_i_want_to_test(request.getHeader(), numberInput);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
protected Dossier method_i_want_to_test(Header srcHeader, Long numberInput) throws SOAException {
Header header = generateHeaderForServiceCall(inputA,srcHeader,inputF,inputJ,inputK);
OtherServiceRequest request = new OtherServiceRequest();
OtherServiceInput input = new OtherServiceInput();
input.setNumber(numberInput);
request.setInput(input);
request.setHeader(header); // So, you can see the i need the result of generateHeaderForServiceCall method
OtherServiceResponse response = OtherService.process(request);
assertSucessfullResponse(response, "OtherService");
return response;
}
}
我的 ClassB 包含私有和受保护的方法是:
package otherPackage;
...
public class ClassB {
private Header generateHeaderForServiceCall(InputA inputA,Header srcHeader,InputF inputF,InputJ inputJ,InputK inputK) throws ServiceException {
String[] nameInfo = QNameUtil.getServiceQNameInfo(inputA);
String serviceVersion = auxMethod(inputJ, inputF);
//... do more stuff
return result;
}
}
还有我的 class 测试,我使用 PowerMock 测试私有方法,如果方法受保护则尝试使用 Mockito。之后我会解释当我 运行 两个测试时我得到了什么:
package package;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.doReturn;
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassA.class)
public class MyTest {
@InjectMocks
private ClassA classA;
@Mock
private InputA inputA;
@Mock
private InputB inputB;
@Mock
private InputC inputC;
@Mock
private InputD inputD;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
classA = new classA( inputA, inputB,inputC, inputD);
}
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = Aux.createDefaultHeader();
//create the spy of my ClassA
classA spy = PowerMockito.spy(classA);
// Define what I want the method 'generateHeaderForServiceCall' returns when called
doReturn(defaultHeader).when(spy, "generateHeaderForServiceCall", inputA,defaultHeader,inputF,inputJ,inputK);
// I try to call the method 'method_i_want_to_test' with classA variable @Injected and with spy of ClassA
//classA.method_i_want_to_test(defaultHeader,inputNumber);
spy.method_i_want_to_test(defaultHeader,inputNumber);
}
}
1 - 当我 运行 这个 processPrivateMethod 在调试方法中测试时,当 generateHeaderForServiceCall 被调用时,它会尝试执行该方法的逻辑并失败,因为 header 是一个基本方法。但我尝试做的是模拟这个,只是 return 默认 Header 没有逻辑。
2- 如果我将 generateHeaderForServiceCall 更改为像 ClassB 的某些方法一样进行保护,并为此使用 mockito:
@Test
public void processProtectedMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
when(classA.generateHeaderForServiceCall(inputA,defaultHeader,"ccccccc","dxdx",5464564)).thenReturn(defaultHeader);
classA.method_i_want_to_test(defaultHeader,inputNumber);
}
但它 return 一个错误,因为该方法是受保护的(如果它是私有的并且我使用 mockito,则同样的错误)。
Error: java: generateHeaderForServiceCall(....) has protected access
in package
尝试次数:
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
// Partial mock to mock methods in parent class
child = new ClasseA(...){
@Override
protected Header generateHeaderForServiceCall(...) throws ServiceException {
//mock logic here
return aux.createDefaultHeader();;
}
};
}
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = aux.createDefaultHeader();
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
2-
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
child = PowerMockito.spy(new ClasseA(...));
PowerMockito.doReturn(defaultHeader).when(child, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
3-
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
child = PowerMockito.spy(new ClassA(...));
father = PowerMockito.spy(new ClasseB());
PowerMockito.doReturn(defaultHeader).when(father, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
没有人做我想做的事。全部进入 classB 中的 generateHeaderForServiceCall 方法并尝试执行内部逻辑。
谢谢
听起来您正在寻找 spy
。
So, can i do with with Mockito?
Do i need to use PowerMock?
如果它是私有的你需要使用 PowerMockito
,
如果其受保护的 Mockito
可以处理它。
Can i use Mockito and PowerMockito together?
PowerMockito
建立在 Mockito
的基础上,所以是的。
请注意 spy
应谨慎使用,例如用于测试遗留代码。
通常的建议是重构您的代码。
@PrepareForTest
Annotation 需要包含 class
字节码被修改的地方 Class A
.
使用 PowerMockito
和 JUnit4
进行模拟的私有方法:
这里是一个使用 String
return 而不是 Header
的简化示例:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Test.A.class)
public class Test {
static class A extends B {
public String process() {
return "y" + method_i_want_to_test();
}
}
static class B {
private String generateHeaderForServiceCall() {
return "abc";
}
protected String method_i_want_to_test() {
return "x" + generateHeaderForServiceCall();
}
}
@Spy
A classUnderTest = new A();
@Test
public void testCustomExceptionIsThrown() throws Exception {
PowerMockito.doReturn("123").when(classUnderTest, "generateHeaderForServiceCall");
Assert.assertEquals("yx123", classUnderTest.process());
}
}
使用 Mockito
和 JUnit5
进行模拟的受保护方法:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class Test {
static class A extends B {
public String test() {
return generateHeaderForServiceCall();
}
}
static class B {
protected String generateHeaderForServiceCall() {
return "abc";
}
}
@Spy
A classUnderTest;
@Test
public void testCustomExceptionIsThrown() throws Exception {
Mockito.when(classUnderTest.generateHeaderForServiceCall()).thenReturn("123");
Assertions.assertEquals("123", classUnderTest.test());
}
}
我想用 JMockit 做一些类似于 'MockUp' 的事情,但是使用 Mockito。
我想控制扩展 class 我想测试的 class 方法的行为。 但我有一个问题,那就是该方法是私有的,所以我认为我不能使用 Mockito,需要使用 PowerMock。
问题
Class A extends B{...}
Class B {
private Header generateHeaderForServiceCall(c,d,f,g,h,j){...}
}
在我的 Class ATest{ 在 @Before 中,我想模拟 generateHeaderForServiceCall(.....) 只为 return 创建一个默认的 Header对我来说。 }
因此,使用 JMockit 就像:
new MockUp<Controller>() {
@Mock
private Header generateHeaderForServiceCall(...) {
return defaultHeader;
}
};
我会更好地说明我的上下文:
public class B {
private Header generateHeaderForServiceCall(Input A, Input B, Input c, Input D) throws ServiceException {
......
//do stuff
return header}
}
public class A extends B {
@Override
public Response process(Request request) throws SOAException {
//do stuff
try {
method_i_want_to_test(Input A, Input B);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
protected Dossier method_i_want_to_test(Input A, Input B) throws
SOAException {
... //do stuff
**Header** **header** = generateHeaderForServiceCall(Input A, Input
B,Input c, Input D);**
// **doLogic** with header returned and return the result
}
}
我想做什么:
private A aTest;
@Before
public void setUp() throws Exception {
PowerMockito.mock(aTest);
PowerMockito.doReturn(defaultHeader).when(aTest,"generateHeaderForServiceCall", params);
}
因此,当我转到 method_i_want_to_test 并调用 generateHeaderForServiceCall 时,我只想获得默认值 header,而忽略方法的输入和逻辑。我想模拟这个方法,但是它 private/protected.
那么,我可以使用 Mockito 吗?
我需要使用 PowerMock 吗?
我可以同时使用 Mockito 和 PowerMockit 吗?
------------------------------------ 更新----------------------------
所以,我的 classA,我想测试的是:
package mypackage;
import package.ClassB;
@Service
public class ClassA extends ClassB implements Xinterface {
@Inject
public ClassA(InputA inputA, InputB inputB,InputC inputC, InputD inputD) {
...
}
@Override
public ClassAResponse process(ClassARequest request) throws SOAException {
ClassAResponse response = initResponse(inputA, request, new ClassAResponse());
ClassAInput input = request.getInput();
ClassAOutput output = new ClassAOutput();
response.setOutput(output);
try {
/* */
method_i_want_to_test(request.getHeader(), numberInput);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
protected Dossier method_i_want_to_test(Header srcHeader, Long numberInput) throws SOAException {
Header header = generateHeaderForServiceCall(inputA,srcHeader,inputF,inputJ,inputK);
OtherServiceRequest request = new OtherServiceRequest();
OtherServiceInput input = new OtherServiceInput();
input.setNumber(numberInput);
request.setInput(input);
request.setHeader(header); // So, you can see the i need the result of generateHeaderForServiceCall method
OtherServiceResponse response = OtherService.process(request);
assertSucessfullResponse(response, "OtherService");
return response;
}
}
我的 ClassB 包含私有和受保护的方法是:
package otherPackage;
...
public class ClassB {
private Header generateHeaderForServiceCall(InputA inputA,Header srcHeader,InputF inputF,InputJ inputJ,InputK inputK) throws ServiceException {
String[] nameInfo = QNameUtil.getServiceQNameInfo(inputA);
String serviceVersion = auxMethod(inputJ, inputF);
//... do more stuff
return result;
}
}
还有我的 class 测试,我使用 PowerMock 测试私有方法,如果方法受保护则尝试使用 Mockito。之后我会解释当我 运行 两个测试时我得到了什么:
package package;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.doReturn;
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassA.class)
public class MyTest {
@InjectMocks
private ClassA classA;
@Mock
private InputA inputA;
@Mock
private InputB inputB;
@Mock
private InputC inputC;
@Mock
private InputD inputD;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
classA = new classA( inputA, inputB,inputC, inputD);
}
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = Aux.createDefaultHeader();
//create the spy of my ClassA
classA spy = PowerMockito.spy(classA);
// Define what I want the method 'generateHeaderForServiceCall' returns when called
doReturn(defaultHeader).when(spy, "generateHeaderForServiceCall", inputA,defaultHeader,inputF,inputJ,inputK);
// I try to call the method 'method_i_want_to_test' with classA variable @Injected and with spy of ClassA
//classA.method_i_want_to_test(defaultHeader,inputNumber);
spy.method_i_want_to_test(defaultHeader,inputNumber);
}
}
1 - 当我 运行 这个 processPrivateMethod 在调试方法中测试时,当 generateHeaderForServiceCall 被调用时,它会尝试执行该方法的逻辑并失败,因为 header 是一个基本方法。但我尝试做的是模拟这个,只是 return 默认 Header 没有逻辑。
2- 如果我将 generateHeaderForServiceCall 更改为像 ClassB 的某些方法一样进行保护,并为此使用 mockito:
@Test
public void processProtectedMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
when(classA.generateHeaderForServiceCall(inputA,defaultHeader,"ccccccc","dxdx",5464564)).thenReturn(defaultHeader);
classA.method_i_want_to_test(defaultHeader,inputNumber);
}
但它 return 一个错误,因为该方法是受保护的(如果它是私有的并且我使用 mockito,则同样的错误)。
Error: java: generateHeaderForServiceCall(....) has protected access in package
尝试次数:
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
// Partial mock to mock methods in parent class
child = new ClasseA(...){
@Override
protected Header generateHeaderForServiceCall(...) throws ServiceException {
//mock logic here
return aux.createDefaultHeader();;
}
};
}
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = aux.createDefaultHeader();
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
2-
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
child = PowerMockito.spy(new ClasseA(...));
PowerMockito.doReturn(defaultHeader).when(child, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
3-
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
child = PowerMockito.spy(new ClassA(...));
father = PowerMockito.spy(new ClasseB());
PowerMockito.doReturn(defaultHeader).when(father, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
没有人做我想做的事。全部进入 classB 中的 generateHeaderForServiceCall 方法并尝试执行内部逻辑。 谢谢
听起来您正在寻找 spy
。
So, can i do with with Mockito? Do i need to use PowerMock?
如果它是私有的你需要使用 PowerMockito
,
如果其受保护的 Mockito
可以处理它。
Can i use Mockito and PowerMockito together?
PowerMockito
建立在 Mockito
的基础上,所以是的。
请注意 spy
应谨慎使用,例如用于测试遗留代码。
通常的建议是重构您的代码。
@PrepareForTest
Annotation 需要包含 class
字节码被修改的地方 Class A
.
使用 PowerMockito
和 JUnit4
进行模拟的私有方法:
这里是一个使用 String
return 而不是 Header
的简化示例:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Test.A.class)
public class Test {
static class A extends B {
public String process() {
return "y" + method_i_want_to_test();
}
}
static class B {
private String generateHeaderForServiceCall() {
return "abc";
}
protected String method_i_want_to_test() {
return "x" + generateHeaderForServiceCall();
}
}
@Spy
A classUnderTest = new A();
@Test
public void testCustomExceptionIsThrown() throws Exception {
PowerMockito.doReturn("123").when(classUnderTest, "generateHeaderForServiceCall");
Assert.assertEquals("yx123", classUnderTest.process());
}
}
使用 Mockito
和 JUnit5
进行模拟的受保护方法:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class Test {
static class A extends B {
public String test() {
return generateHeaderForServiceCall();
}
}
static class B {
protected String generateHeaderForServiceCall() {
return "abc";
}
}
@Spy
A classUnderTest;
@Test
public void testCustomExceptionIsThrown() throws Exception {
Mockito.when(classUnderTest.generateHeaderForServiceCall()).thenReturn("123");
Assertions.assertEquals("123", classUnderTest.test());
}
}