我有一个场景,我必须在父类中模拟一个方法。从被测方法调用该方法。我无法使用jMockit来模拟函数。
我的超级课程方法如下
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
// Email recipients code. I want to mock this function.
}
}
我的子类如下
public class MyClass extends SuperClass {
public void methodUnderTest(HttpServletRequest request) {
// Some code here.
List<String> recipients = new ArrayList<>();
recipients.add("foo@example.com");
recipients.add("bar@example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
我尝试过使用partial mocks using jMockit's tutorial,但它对我没用。我的测试方法如下。
更新:我按照以下方式实施了Rogerio的建议。实现仍然称为真正的方法。当我在Eclipse中调试mocked类的实例时,这就是我看到的com.project.web.mvc.$Subclass_superClass@6b38c54e
@Test
public void testMethodUnderTest(@Mocked final SuperClass superClass) throws Exception {
final MyClass myClass = new MyClass();
new Expectations(myClass) {{
// .. Other expectations here
superClass.emailRecipients((List<String>) any);
}};
MockHttpServletRequest req = new MockHttpServletRequest();
myClass.methodUnderTest(req);
}
问题在于,当我尝试模拟emailRecipients
的调用时,它总是试图调用实际的函数。我正在使用Java 7,jMockit v1.35和Maven 3x进行构建。
更新代码是遗留代码。因此,我们无法更新它。我们不能使用PowerMock,因为它不属于公司批准的库。我们可以使用jMockit或Mockito或两者的组合。
答案 0 :(得分:0)
见下面的例子
P.S。使用Mockito.any(HttpServletRequest.class)代替Mockito.any(ArrayList.class)代码
超级
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
System.out.println("Emailed!");
}
}
MyClass的
public class MyClass extends SuperClass {
public void methodUnderTest() {
// Some code here.
ArrayList<String> recipients = new ArrayList<>();
recipients.add("foo@example.com");
recipients.add("bar@example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
测试类
public class TestCase {
MyClass myClass = Mockito.mock(MyClass.class, Mockito.CALLS_REAL_METHODS);
@Before
public void prepare() {
PowerMockito.doNothing().when(myClass).emailRecipients(Mockito.any(ArrayList.class));
/*PowerMockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Custom code");
return null;
}
}).when(myClass).emailRecipients(Mockito.any(ArrayList.class));*/
}
@Test
public void testMethodUnderTest() throws Exception {
myClass.methodUnderTest();
}
}
如果您不想执行emailRecipients中的代码,请使用doNothing() 否则使用doAnswer执行其他一些代码
答案 1 :(得分:0)
您想要从父类模拟方法的事实表明您的方法未通过关注点分离/单一责任模式(SoC / SRP)。
使用Rajiv Kapoor建议的 PowerMock 是可能的,但这(因为任何 PowerMock 的使用)都会让人觉得设计不好。
您可以通过应用偏好合成而不是继承原则(FCoI)来解决您的设计问题。
要做到这一点,你要将你的(最有可能的)抽象超级班级变成一个正常的&#34;类。您创建了一个接口,它声明了超类中的所有public
和abstract
方法。您的子类不再扩展父类,而是实现接口。它会将前父类的实例作为 dependency 并将其调用为根据需要提供常见行为的方法。
这种依赖关系很容易被模拟,而不需要 PowerMock 。
更新代码是遗留代码。因此,我们无法对其进行更新。
在这种情况下,你会被摧毁。
您拥有的代码不是 unittestable ,因为它是以不可测试的方式编写的。您唯一的机会是编写模块和/或验证测试(不使用模拟框架),覆盖代码中的每个执行路径。
这个测试创建起来会很昂贵并且速度很慢,但是在稍后将代码重构为可测试的(== changable)时,它们将会保留你的测试。