【问题标题】:Mockito: how to stub getter setterMockito:如何存根 getter setter
【发布时间】:2012-04-18 20:53:06
【问题描述】:

我是 Mockito 的新手,我想知道如何存根获取/设置对。

例如

public interface Dummy {
     public String getString();
     public void setString(String string);
}

我怎样才能让它们正常运行:如果在某个测试中调用setString("something"); 我希望getString() 返回“某物”。这是可行的还是有更好的方法来处理这种情况?

【问题讨论】:

  • 您是否有理由要模拟 Dummy 并且不能只使用常规对象来实现它?
  • @milkplusvellocet 说了什么。另外,如果你真的想要/需要测试一个 setter,那么你做错了测试和/或 setter。
  • @milkplusvellocet 实际上我正在存根 HttpServletRequest 并且我希望 characterSetEncoding 属性能够工作。使用常规对象要实现的方法太多了。这让我想,我们可以模拟抽象类吗?如果是这样,那么这对我来说是一个解决方案。我明天会调查,我没有工作空间。
  • @PhilippReichart 我不想测试 getter/setter,我只想让它工作。也许使用抽象类可以解决我的问题?
  • @GuillaumePolet 好的,这是一个正当的理由 :) 也许 Mockito's capture support 可以帮助你?

标签: java testing mockito


【解决方案1】:

我还希望 getter 返回最近 setter 调用的结果。

拥有

class Dog
{
    private Sound sound;

    public Sound getSound() {
        return sound;
    }
    public void setSound(Sound sound)   {
        this.sound = sound;
    }
}

class Sound
{
    private String syllable;

    Sound(String syllable)  {
        this.syllable = syllable;
    }
}

我使用以下方法将 setter 连接到 getter:

final Dog mockedDog = Mockito.mock(Dog.class, Mockito.RETURNS_DEEP_STUBS);
// connect getter and setter
Mockito.when(mockedDog.getSound()).thenCallRealMethod();
Mockito.doCallRealMethod().when(mockedDog).setSound(Mockito.any(Sound.class));

【讨论】:

    【解决方案2】:

    我能想到三种可能的方法。

    1. 不要在你的应用程序中直接使用HttpServletRequest;为它创建一个包装类,并为包装类提供一个接口。无论您当前在应用程序中的何处使用HttpServletRequest,请改用该界面。然后在测试中,有这个接口的替代实现。然后,您根本不需要 Mockito 模拟。

    2. 在您的测试类中有一个字段,用于存储您已将 String 设置为的值。制作两个 Mockito Answer 对象;一个在调用getString 时返回该字段的值,另一个在调用setString 时设置该字段的值。以通常的方式制作一个模拟,并将其存根以使用这两个答案。

    3. 创建一个抽象类(可以是测试类的静态内部类),实现HttpServletRequest 接口,但具有您要设置的字段,并定义getter 和setter。然后模拟抽象类,并将 Mockito.CALLS_REAL_METHODS 作为默认答案传入。当你在 mock 上调用 getter 或 setter 时,真正的方法会启动,这就是你想要的行为。

    希望这三种选择中的一种能够满足您的需求。

    【讨论】:

    • HttpSevletRequest 实际上是一个接口,唯一的问题是它有太多的方法要实现而无法做到这一点。对于第二种选择,这可能是最好的方法。我宁愿使用只定义这两种方法的抽象类。我将发布我选择的解决方案。
    • 哎呀,对不起,我忘了那是一个界面。我不再确定选项 1;我需要更多地了解你的代码才能知道我是否可以让它工作。您想尝试选项 2 吗?如果您需要,我很乐意为您提供帮助。
    • 其实我觉得在Mockito中使用抽象类是可以的。我所要做的就是表明我想为 getter 和 setter 调用“真实方法”。我发现这个链接可能很有趣:marcschwieterman.com/blog/…
    • 对,你可以模拟抽象类,使用CALLS_REAL_METHODS默认答案。如果我没记错的话,如果任何抽象方法最终被调用,你会得到一个运行时异常,但这应该不是问题,对吧?
    • 我试过了,效果很好。我有一些没有被存根但被调用的方法,这似乎不是问题。您是否愿意使用此解决方案更新您的答案?否则我会回答我自己的问题,但我不想那样做
    【解决方案3】:

    我发现这很好用:

    doAnswer(answer -> when(dummy.getString()).thenReturn((String) answer.getArguments()[0]))
        .when(dummy).setString(any());
    

    我必须使用 doAnswer(..).when(..) 因为 setter 是一个 void 方法。当 setter 被一个对象调用时,getter 将被设置为响应同一个对象。

    当您有接口但没有实现时非常有用。

    【讨论】:

      【解决方案4】:

      在这种 HttpServletRequest 存根的特殊情况下,我强烈建议使用 Spring-Mock 框架: (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/mock/web/package-summary.html)

      它具有用于基于 Web 的操作的内置模拟。

      否则,请使用 Answer 为您的模拟对象定义您自己的响应 (http://mockito.googlecode.com/svn/branches/1.8.5/javadoc/org/mockito/stubbing/Answer.html)

      【讨论】:

        【解决方案5】:

        我遇到了这个问题,但不想接受已接受的答案,因为这样做会停止嘲笑我的 bean 中的 所有 getter 和 setter。我想要的只是为单个 getter/setter 对创建存根,而不是全部。因此,我使用了以下代码。

        @Mock
        private Dummy mockDummy;
        private final MutableObject<String> stringWrapper = new MutableObject<>();
        
        public TestClass() {
            MockitoAnnotations.initMocks(this);
        
            doAnswer(invocationOnMock -> {
                String injectedString = (String)invocationOnMock.getArguments()[0];
                TestClass.this.stringWrapper.setValue(injectedString);
                return null;
            }).when(this.mockDummy).setString(any());
            when(this.mockDummy.getString()).thenAnswer(
                    invocationOnMock -> TestClass.this.stringValue.getValue());
        }
        

        第一个 lambda 实现了 Answer&lt;Void&gt; 匿名类'answer() method。因此,每当 setter 方法由被测代码执行时,该 setter 的存根将其记录到 MutableObject 帮助器对象中。然后,getter 实现可以返回这个记录的值。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-13
          • 1970-01-01
          • 1970-01-01
          • 2019-01-07
          • 1970-01-01
          • 2023-03-07
          相关资源
          最近更新 更多