我正在寻找一个合适的模拟工具来模拟内部状态(例如void方法)。我知道Powermock和JMock可以做到这一点,但我还没有做出选择。我有更多使用EasyMock的经验,但没有尝试嘲笑内部状态。我不太确定它是否天生支持。我还在搜索它的文档。
答案 0 :(得分:3)
通过内部状态,我假设您可能意味着您的公共方法调用以执行其工作的一些私有或包私有方法。在我看来,如果你内部调用的方法非常复杂,你想要把它嘲笑出去,那么你应该把它拉出来放在它自己的类中,单独测试那个类,然后将它作为服务注入原始类你想要作为一项服务进行测试。
所以你的课看起来像这样,你想测试someMethod
。
public class Original {
public void someMethod() {
// ... stuff
Object someValue = callComplicatedPrivateMethod();
// ... more stuff
}
}
我会改为:
public class Original {
private ComplicatedService service;
public Original(ComplicatedService service) {
this.service = service;
}
public void someMethod() {
// ... stuff
Object someValue = service.callComplicatedMethod();
// ... more stuff
}
}
现在您可以轻松(通常)模拟ComplicatedService
并正常测试您的Original
课程。
答案 1 :(得分:2)
假设你有一个这样的类,你有一个讨厌的内部状态(通过一个名为doSomething
的方法访问)并且它阻止你测试myMethod
。
public class Me {
public int myMethod () {
doSomething();
return 7;
}
void doSomething() {
// Access some internal state which is hard to mock
}
}
你可以通过在测试中覆盖它来解决这个问题。
@Test
public void testMyMethod () {
Me fixture = new Me() {
@Override
void doSomething() {
}
}
Assert.assertEquals(7, fixture.myMethod());
}
使用Mockito,您可以使用spy
和doAnswer
实现相同目标。例如。
Me me = new Me(); // the original fixture
Me mySpy = spy(me); // a spied version when you can copy the behaviour
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock inv) throws Throwable {
throw new Exception("Hello!");
}
}).when(mySpy).doSomething();
// Will throw an exception or obviously whatever you put in the body of the answer method
mySpy.doSomething();
答案 2 :(得分:0)
我最近使用EasyMock实现了对我们正在进行的项目的内部方法的模拟。这是在EasyMock文档之后实现的。请参阅EasyMock documentation中 Partial Mocking 部分。
以下是我编写单元测试的方法:
让我们假设类getTopNVideosByTagNameAndProperty
中的API VideoAPI
需要进行单元测试,并且此方法在内部调用同一个类getVideosByTagName
中的另一个公共方法。内部方法接受一个参数并返回一个List。方法getVideosByTagName
必须使用EasyMock的模拟构建器进行模拟。
<强> CODE 强>:
//create the mock object with the help of Mock Builder and then add the method to be mocked.
VideoAPI videoApi=EasyMock.createMockBuilder(Video.class).addMockedMethod("getVideosByTagName").createMock();
String tagName ="sometag"; // create the paramter
// create a dummy return object you expect from the internal method getVideosByTagName
List listVideos = new ArrayList();
for (int i = 1; i <=10; i++) { //populate listVideos }
//set up the EasyMock for the mocked method call
EasyMock.expect(videoApi.getVideosByTagName(tagName)).andReturn(listVideos).anyTimes();
EasyMock.replay(videoApi);
//now call the actual method to be tested - in this case it returns top 5 videos
List<Video> listVideoTopN = videoApi.getTopNVideosByTagNameAndProperty("tag", "likes", 5);
//do the asserts
assertNotNull(listVideoTopN);
assertEquals(5, listVideoTopN.size());
//finally verify the mocks
EasyMock.verify(videoApi);
这对我来说非常好。