如何使用jMockit

时间:2017-09-28 17:12:19

标签: java unit-testing jmockit

我有一个场景,我必须在父类中模拟一个方法。从被测方法调用该方法。我无法使用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或两者的组合。

2 个答案:

答案 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;类。您创建了一个接口,它声明了超类中的所有publicabstract方法。您的子类不再扩展父类,而是实现接口。它会将前父类的实例作为 dependency 并将其调用为根据需要提供常见行为的方法。

这种依赖关系很容易被模拟,而不需要 PowerMock

  

更新代码是遗留代码。因此,我们无法对其进行更新。

在这种情况下,你会被摧毁。

您拥有的代码不是 unittestable ,因为它是以不可测试的方式编写的。您唯一的机会是编写模块和/或验证测试(不使用模拟框架),覆盖代码中的每个执行路径。

这个测试创建起来会很昂贵并且速度很慢,但是在稍后将代码重构为可测试的(== changable)时,它们将会保留你的测试。