Mockito 重新存根方法已使用 thenthrow 存根

发布于 2024-10-02 14:27:47 字数 422 浏览 1 评论 0原文

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

问题是,我的 getLoggedInUser() 方法也可能引发 AuthenticationException。

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

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

引发异常,因为 userProvider.getLoggedInUser() 已被 thenTrow()

存根如何告诉 when 方法不关心异常?

提前致谢 - István

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.

The problem is, that my getLoggedInUser() method can also throw an 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()

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

Thanks in advance - István

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

抠脚大汉 2024-10-09 14:27:47

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

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

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

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

澉约 2024-10-09 14:27:47

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

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

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

因此,就您的情况而言,我预计至少会看到两次测试。一种是 getLoggedInUser() 返回用户,另一种是 getLoggedInUser() 抛出异常。这样,您在尝试模拟模拟中的不同行为时就不会遇到问题。

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

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.

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.

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.

久夏青 2024-10-09 14:27:47

有什么方法可以告诉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 命令。

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

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

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

    }
}

TestB fails due to the assert that you can't get rid of. TestC shows how the reset method can be used to reset the mock and remove the thenThrow command on it.

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.mock rather than Mockito.mock?

圈圈圆圆圈圈 2024-10-09 14:27:47

使用 Mockito.reset() 重置任何特定的模拟,例如 Mockito.reset(mock1, mock2)

检查更多详细信息:https://stackoverflow.com/a/68126634/12085680

例如:

    @Test
    void test() {   
    when(mock.someMethod(any())).thenThrow(SomeException.class);
    // Using a service that uses the mock inside for example
    assertThrows(SomeException.class, () -> service.someMethodThatUsesTheMock("test"));
    Mockito.reset(mock); // reset it so you can reuse that mock on another test
    }

Use Mockito.reset() to reset any particular mocks, for example Mockito.reset(mock1, mock2)

Check for more detail: https://stackoverflow.com/a/68126634/12085680

For example:

    @Test
    void test() {   
    when(mock.someMethod(any())).thenThrow(SomeException.class);
    // Using a service that uses the mock inside for example
    assertThrows(SomeException.class, () -> service.someMethodThatUsesTheMock("test"));
    Mockito.reset(mock); // reset it so you can reuse that mock on another test
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文