java Mockito 重新存根方法已经用 thenthrow 存根

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4180209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 05:11:27  来源:igfitidea点击:

Mockito re-stub method already stubbed with thenthrow

javamockingmockitostubbing

提问by Sobvan

I ran into a problem with mockito. I am developing a web application. In my tests the user management is mocked. There are some cases when I have to alter the User returned by the getLoggedInUser()method.

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

The problem is, that my getLoggedInUser()method can also throw an AuthenticationException.

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

So when I try to switch from no user to some user, the call to

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

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

throws an exception, as userProvider.getLoggedInUser()is already stubbed with thenTrow()

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

Is there any way for to tell the whenmethod not to care about exceptions?

有什么方法可以告诉when方法不关心异常吗?

Thanks in advance - István

提前致谢 - István

采纳答案by drekka

My first reaction to your question is that it sounds like you are trying to do too much in one test.

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

For ease of testing and simplicity each test should test one thing only. This is the same as the Single Responsibility Principle. I often find programmers trying to test multiple things in one test and having all sorts of problems because of it. So each of your unit test methods should follow this flow:

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

  1. Setup a single scenario for the test.
  2. Make a call to the class being tested to trigger the code being tested.
  3. Verify the behaviour.
  1. 为测试设置单个场景。
  2. 调用被测试的类来触发被测试的代码。
  3. 验证行为。

So in your case I would expect to see at least two tests. One where getLoggedInUser()returns a user, and one where getLoggedInUser()throws an exception. That way you will not have problems with trying to simulate different behaviour in the mock.

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

The second thought that spring to mind is not to stub. Look into using expect instead because you can setup a series of expectation. I.e. the first call returns a user, the second call throws an exception, the third call returns a different user, etc.

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

回答by Bogdan Sulima

In new Mockito versions you can use stubbing consecutive calls to throw exception on first can and returning a value on a second call.

在新的 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

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

回答by Pod

Is there any way for to tell the when method not to care about exceptions?

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

To actually answer this question:

要真正回答这个问题:

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> {

    }
}

TestBfails due to the assert that you can't get rid of. TestCshows how the resetmethod can be used to reset the mock and remove the thenThrowcommand on it.

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

Note that reset doesn't always seem to work in some more complicated examples I have. I suspect it might be because they're using PowerMockito.mockrather than Mockito.mock?

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

回答by javamonkey79

It sounds like you may have to use a custom answer. Here is an example.

听起来您可能必须使用自定义答案。这是一个例子