我有一些使用Mockito的测试代码(见下文),但是,我认为我需要切换到更强大的JMockit来实现我的测试。
但是,如果我在Session类上使用@Tested
注释,则从构造函数调用的init方法会抛出异常。
如果我在Session类上使用@Mocked
,我就没有可用于测试的真实方法。
下面未显示的是我还需要在测试期间访问details
对象。但是,这在构造函数期间从plugin
对象检索,构造函数调用有问题的init
方法。
如何使用JMockit测试checkDetails
方法?
测试代码
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
public class SessionTest {
@Test
public void testSession() {
Session session = Mockito.mock(Session.class);
Mockito.doCallRealMethod().when(session).checkDetails(Mockito.any(String.class));
Assert.assertEquals(session.checkDetails("Foo"), true);
}
}
要测试的课程
import java.net.Socket;
import java.net.SocketException;
import java.util.List;
public class Session {
private final Socket socket;
private final List<String> details;
private final Plugin plugin;
public Session(Socket socket, Plugin plugin) throws SocketException {
this.socket = socket;
this.plugin = plugin;
this.details = plugin.getDetails();
init();
}
public void init() throws SocketException {
socket.setTcpNoDelay(true);
}
public boolean checkDetails(String item) {
for (String detail : details) {
if (detail.equals(item)) {
return true;
}
}
return false;
}
}
依赖
import java.util.List;
public class Plugin {
private List<String> details;
public List<String> getDetails() {
return details;
}
}
注意:这是一个非常简化的代码版本,目前无法更改生产代码。
答案 0 :(得分:0)
我不会亲自用部分嘲笑来进行这个测试。这不是您想要部分模拟测试中的代码的情况。 (我只是在我有一个实用工具方法的情况下模拟CUT我独立测试,我想假设实用方法工作得很好,并测试更大的上下文。你不是在这里做的。)
我会采取两种方法中的一种,具体取决于我的目标。
将构造函数视为您正在测试的内容的一部分:
@RunWith(JMockit.class)
public class SessionTest {
@Injectable Socket socket;
@Injectable Plugin plugin;
@Test
public void testCheckDetails() throws Exception {
new Expectations() {{
plugin.getDetails(); result = Arrays.asList("Foo", "Bar", "Baz");
}};
Session session = new Session(socket, plugin);
boolean b = session.checkDetails("Foo");
assertThat(b, is(true));
}
}
假设对象构造正确并且正确初始化了List<String> details
字段。
@RunWith(JMockit.class)
public class SessionTest {
@Tested
Session cut;
@Injectable Socket socket;
@Injectable Plugin plugin;
@Test
public void testCheckDetails() throws Exception {
List<String> details = Arrays.asList("Foo", "Bar", "Baz");
Deencapsulation.setField(cut, details);
boolean b = cut.checkDetails("Foo");
assertThat(b, is(true));
}
}
如果这没有削减它,你真的有你的心脏部分嘲笑(例如你没有完整的故事,你真的需要这样做),这是它的工作方式。假设我们在Session
上还有一个方法:
public List<String> getDetails() {
return plugin.getDetails();
}
让我们进一步假设checkDetails
参考这个辅助方法,而不是实例中的字段。
public boolean checkDetails(String item) {
for (String detail : getDetails()) {
if (detail.equals(item)) {
return true;
}
}
}
然后使用部分模拟的测试可能如下所示:
@RunWith(JMockit.class)
public class SessionTest {
@Tested
Session cut;
@Injectable Socket socket;
@Injectable Plugin plugin;
@Test
public void testCheckDetails() throws Exception {
new Expectations(cut) {
{
cut.getDetails(); result=Arrays.asList("Foo", "Bar", "Baz");
}
};
boolean b = cut.checkDetails("Foo");
assertThat(b, is(true));
}
}
或者,您可以使用假货。同样,getDetails()
方法的假设与上一节相同:
@RunWith(JMockit.class)
public class SessionTest {
@Tested
Session cut;
@Injectable Socket socket;
@Injectable Plugin plugin;
@Test
public void testCheckDetails() throws Exception {
new MockUp<Session>() {
@Mock
List<String> getDetails() {
return Arrays.asList("Foo", "Bar", "Baz");
}
};
Session cut = new Session(socket, plugin);
boolean b = cut.checkDetails("Foo");
assertThat(b, is(true));
}
}
请注意,在所有情况下,当您开始部分模拟或伪造对象时,默认操作是为该部分模拟或伪造做真正的实现。只有明确模拟/伪造的方法才会被嘲笑或伪造。这与您使用的Mockito方法形成对比,其中有明确的doCallRealMethod()
(如果没有它,您将调用模拟方法)。
此外,assertThat(...)
内容不是JMockit的一部分;它是JUnit的一部分,就是我喜欢做我的测试的方式,而且我懒得回去把它改成你所拥有的断言。
答案 1 :(得分:0)
等同于Session session = Mockito.mock(Session.class);
的JMockit是
Session session = new MockUp<Session>() {}.getMockInstance();
或
@Mock
Session session;
正如@dcsohl在回答中提到的,没有直接等同于Mockito.doCallRealMethod().when(session).checkDetails(Mockito.any(String.class));
但是,您可以使用MockUp
方法来使用所有实际方法,然后指定要排除的方法。在这种情况下,init
方法是模拟的主要原因以及我们需要排除被调用的内容。
new MockUp<Session>() {
@Mock
public void init() {
//Don't call the real init
}
};
session = new Session(mockPlugin, mockSocket);
请注意,在这种情况下,我们不会在MockUp上调用getMockInstance
。但是,当我们在下一行中的所有contstructor时,JMockit将创建Mock。