Mockito重新存根方法已经与therowrow陷入困境

时间:2010-11-14 23:00:39

标签: java mocking mockito stubbing

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

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

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

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

抛出异常,因为userProvider.getLoggedInUser()已经与thenTrow()

一起存根

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

提前致谢 - István

4 个答案:

答案 0 :(得分:14)

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

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

http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#stubbing_consecutive_calls

答案 1 :(得分:4)

  

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

要真正回答这个问题:

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命令。

请注意,重置并不总是在我有一些更复杂的例子中起作用。我怀疑这可能是因为他们使用PowerMockito.mock而不是Mockito.mock

答案 2 :(得分:3)

我对你的问题的第一反应是听起来你试图在一次测试中做太多。

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

  1. 为测试设置单个方案。
  2. 调用正在测试的类以触发正在测试的代码。
  3. 验证行为。
  4. 所以在你的情况下,我希望至少看到两个测试。一个getLoggedInUser()返回用户,另一个getLoggedInUser()抛出异常。这样,在模拟中尝试模拟不同的行为就不会有问题。

    第二个想到春天的想法不是存根。请考虑使用expect,因为您可以设置一系列期望。即第一个调用返回一个用户,第二个调用抛出异常,第三个调用返回另一个用户,等等。

答案 3 :(得分:2)

听起来你可能不得不使用自定义答案。 Here is an example