【问题标题】:Mockito re-stub method already stubbed with thenthrowMockito 重新存根方法已经用 thenthrow 存根
【发布时间】:2011-05-09 23:24:34
【问题描述】:

我遇到了 mockito 的问题。 我正在开发一个网络应用程序。在我的测试中,用户管理被嘲笑了。 在某些情况下,我必须更改 getLoggedInUser() 方法返回的用户。

问题是,我的getLoggedInUser() 方法也可以抛出AuthenticationException

所以当我尝试从无用户切换到某个用户时,调用到

when(userProvider.getLoggedInUser()).thenReturn(user);

抛出异常,因为userProvider.getLoggedInUser() 已经被thenTrow() 存根

有没有办法告诉when 方法不要关心异常?

提前致谢 - 伊斯特万

【问题讨论】:

  • 谢谢大家的回答!总结一下:很可能是由于软件设计不佳,我需要重新设置该方法。但是现在对我来说很容易,而且测试看起来也很干净。我做了更多的研究,发现了 Mockito.reset(T...mocks) 方法,这对我有用。下次我会想出一些更简单的设计:)

标签: java mocking mockito stubbing


【解决方案1】:

我对您的问题的第一反应是,听起来您在一次测试中尝试做太多事情。

为了便于测试和简单化,每个测试都应该只测试一件事。这与Single Responsibility Principle 相同。我经常发现程序员试图在一个测试中测试多个东西,并因此而遇到各种各样的问题。所以你的每个单元测试方法都应该遵循这个流程:

  1. 为测试设置单一场景。
  2. 调用正在测试的类以触发正在测试的代码。
  3. 验证行为。

所以在你的情况下,我希望看到至少两个测试。一种是getLoggedInUser() 返回用户,另一种是getLoggedInUser() 抛出异常。这样您就不会在尝试模拟模拟中的不同行为时遇到问题。

第二个想法是不要存根。考虑改用期望,因为您可以设置一系列期望。 IE。第一次调用返回用户,第二次调用抛出异常,第三次调用返回不同的用户,等等。

【讨论】:

  • 将不胜感激使用“期望”或文档/教程链接的示例:)
【解决方案2】:

在新的 Mockito 版本中,您可以使用存根连续调用在第一次调用时抛出异常并在第二次调用时返回值。

when(mock.someMethod("some arg"))
    .thenThrow(new RuntimeException())
    .thenReturn("foo");

https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#10

【讨论】:

    【解决方案3】:

    有没有办法告诉when方法不关心异常?

    要真正回答这个问题:

    import static org.hamcrest.Matchers.equalTo;
    import static org.hamcrest.Matchers.is;
    import static org.junit.Assert.assertThat;
    import static org.mockito.ArgumentMatchers.any;
    import static org.powermock.api.mockito.PowerMockito.mock;
    import static org.powermock.api.mockito.PowerMockito.when;
    
    import org.junit.Test;
    import org.mockito.Mockito;
    
    import java.util.ArrayList;
    
    public class MyTest {
    
        @Test
        public void testA() {
    
            // setup
            ArrayList<Object> list = mock(ObjectArrayList.class);
            when(list.indexOf(any())).thenReturn(6);
            when(list.indexOf(any())).thenReturn(12);
    
            // execute
            int index = list.indexOf(new Object());
    
            // verify
            assertThat(index, is(equalTo(12)));
        }
    
        @Test
        public void testB() {
    
            // setup
            ArrayList<Object> list = mock(ObjectArrayList.class);
            when(list.add(any())).thenThrow(new AssertionError("can't get rid of me!"));
            when(list.add(any())).thenReturn(true);
    
            // execute
            list.add(new Object());
        }
    
        @Test
        public void testC() {
    
            // setup
            ArrayList<Object> list = mock(ObjectArrayList.class);
            when(list.add(any())).thenThrow(new AssertionError("can't get rid of me!"));
            Mockito.reset(list);
            when(list.add(any())).thenReturn(true);
    
            // execute
            list.add(new Object());
        }
    
        /**
         * Exists to work around the fact that mocking an ArrayList<Object>
         * requires a cast, which causes "unchecked" warnings, that can only be suppressed...
         */
        class ObjectArrayList extends ArrayList<Object> {
    
        }
    }
    

    TestB 由于您无法摆脱的断言而失败。 TestC 展示了如何使用reset 方法重置模拟并删除其上的thenThrow 命令。

    请注意,在我拥有的一些更复杂的示例中,reset 似乎并不总是有效。我怀疑这可能是因为他们使用的是PowerMockito.mock 而不是Mockito.mock

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      • 2015-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多