Mockito re-stub方法已使用thenthrow存根

mxg2im7a  于 2022-12-13  发布在  其他
关注(0)|答案(4)|浏览(139)

我遇到了一个mockito的问题。我正在开发一个web应用程序。在我的测试中,用户管理是模拟的。在某些情况下,我必须修改getLoggedInUser()方法返回的用户。
问题是,我的getLoggedInUser()方法也会抛出AuthenticationException
因此,当我尝试从无用户切换到某个用户时,对

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

引发异常,因为userProvider.getLoggedInUser()已使用thenTrow()存根
是否有任何方法可让告知when方法不关心例外状况?
提前感谢- István

n1bvdmb6

n1bvdmb61#

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

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

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

fcg9iug3

fcg9iug32#

我对你的问题的第一React是,听起来你想在一次考试中做太多的事情。
为了测试的方便和简单,每个测试应该只测试一个东西。这和Single Responsibility Principle一样。我经常发现程序员试图在一个测试中测试多个东西,并因此产生各种各样的问题。所以你的每个单元测试方法应该遵循以下流程:
1.为测试设置单个方案。
1.调用被测试的类以触发被测试的代码。
1.验证行为。
因此,在您的例子中,我希望看到至少两个测试。一个是getLoggedInUser()返回一个用户,另一个是getLoggedInUser()抛出一个异常。这样,您就不会在模拟中模拟不同的行为时遇到问题。
第二个想到的不是stub,而是考虑使用expect,因为您可以设置一系列expectation。即,第一个调用返回一个用户,第二个调用引发异常,第三个调用返回不同的用户,等等。

6jjcrrmo

6jjcrrmo3#

有没有办法告诉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失败,因为您无法摆脱Assert。TestC显示了如何使用reset方法重置mock并删除其上的thenThrow命令。
请注意,在我所拥有的一些更复杂的例子中,reset似乎并不总是起作用。我怀疑这可能是因为他们使用的是PowerMockito.mock而不是Mockito.mock

fdbelqdn

fdbelqdn4#

使用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
    }

相关问题