【问题标题】:mock non static method of object which is created not in test method模拟不是在测试方法中创建的对象的非静态方法
【发布时间】:2015-01-13 07:36:11
【问题描述】:

在这种情况下是否可以使用 Mockito、PowerMock 或任何其他模拟对象生成器模拟 RentalProfile.getStartDate()?

我尝试过这样做,但没有成功:

@Test
public void testsetAmortizationModel() throws Exception {
    // ...
    RentalProfile mock = Mockito.mock(RentalProfile.class);
    Mockito.when(mock.getStartDate()).thenAnswer(new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            return "2014-12-21";
        }
    });
    Mockito.verify(mock);
    // ...

}

还有一种方法是调用 RentalProfile.getStartDate()。它不返回“2014-12-21”:

public void classMethod() {
    List<RentalProfile> tPaymentPlans =
    aCompositeAgreement.getRentalProfiles().getRentalProfile();
// ...
    for (RentalProfile tRentalProfile : tPaymentPlans) {
        LocalDate tStartDate = BridgeDateUtils.stringWithHyphenToDate(
            tRentalProfile.getStartDate()); // tRentalProfile is RentalProfile object
// ...
}

【问题讨论】:

  • 您确定您的tRentalProfilemock 是同一个实例吗?如果它是同一个实例,它应该可以工作。当你模拟一个类时,你创建了一个你必须在测试中使用的模拟实例。它不会修改该类所有实例的行为。
  • 你也可以简化模拟:when(mock.getStartDate()).thenReturn("2014-12-21");
  • 做了一些修改。这就是tRentalProfile 的创建方式。

标签: java unit-testing mocking


【解决方案1】:

您发布的代码存在几个问题:

  1. 按照 Vincent 的建议,您可以通过将 Mockito.when(...).thenAnswer(...) 替换为 when(mock.getStartDate()).thenReturn("2014-12-21") 来简化模拟

  2. Mockito.verify(mock); 在这里不是必需的,因为它通常用于检查是否在 mock 上调用了特定方法(带有预期参数)。

  3. 您无处显示模拟已注入您的类实例以方便测试。

以下示例类将正确运行并为您的测试注入依赖项:

public class MyClass {

   private RentalProfile tRentalProfile = null;

   public MyClass(RentalProfile tRentalProfile) {
      this.tRentalProfile = tRentalProfile;
   }

  public void classMethod() {
    // ...
    LocalDate tStartDate = BridgeDateUtils.stringWithHyphenToDate(
      tRentalProfile.getStartDate()); // tRentalProfile is RentalProfile object injected to MyClass
    // ...
  }

}

现在可以通过以下方式使用 Mockito 进行模拟:

@Test
public void testsetAmortizationModel() throws Exception {
    // ...
    RentalProfile mock = Mockito.mock(RentalProfile.class);
    Mockito.when(mock.getStartDate()).thenReturn("2014-12-21");

    MyClass myClass = new MyClass(mock);
    myClass.classMethod();

    // Here you verify whether method has been successfully executed 
    // i.e. verify return value, other class parameters,, mock method calls etc.

}

【讨论】:

  • 重点是我测试了另一个类方法,但其中一些具有需要模拟的本地 RentalProfile 对象。
【解决方案2】:

问题是你的测试中创建的mock实例没有被使用。

@Test
public void testsetAmortizationModel() throws Exception {
    // ...
    RentalProfile mock = Mockito.mock(RentalProfile.class);
    when(mock.getStartDate()).thenReturn("2014-12-21");
    Mockito.verify(mock);
    // ...

    MyClass classToTest = new MyClass(mock);
    classToTest.myMethod();
}

还有你的班级:

public class MyClass {
    private RentalProfile profile;

    public MyClass(RentalProfile profile) { this.profile = profile; }

    public void myMethod() {
        for (RentalProfile tRentalProfile : tPaymentPlans) {
            LocalDate tStartDate = BridgeDateUtils.stringWithHyphenToDate(
                this.profile.getStartDate());
        }
    }
}

您必须解耦变量的创建。您真正要测试的不是RentalProfile 的创建,而是您的方法是否返回此值。

在我的示例中,我选择通过构造函数注入配置文件。

看看这个问题:https://stackoverflow.com/a/25135757/2015239 这是完全相同的问题:你必须解耦代码。

【讨论】:

  • 感谢您的回复,但不好的是我只能更改测试代码。顺便说一句,我在帖子中犯了一个愚蠢的错误。 classMethod() 具有私有访问类型。如果我使用 Whitebox.invokeMethod(Class&lt;?&gt; class, Object... arguments) 调用此方法,您的代码是否会一样工作?
【解决方案3】:

您可以使用 JMockit 库模拟在被测代码中创建的对象,如下所示:

@Test
public void testSetAmortizationModel(@Mocked final RentalProfile mock)
{
    new Expectations() {{ mock.getStartDate(); result = "2014-12-21"; }};

    // No need to pass "mock" into the SUT here; any future instance will be mocked.
    MyClass classToTest = new MyClass();
    classToTest.myMethod();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多