如何使用 Mockito 在两个不同的 cookie 名称时模拟 getCookieByName

How to mock getCookieByName when two different cookie names using Mockito

我想用 mockito 测试这个方法

public boolean verifyState(HttpServletRequest request) {

    String stateToken = getCookieByName(request, STATE_TOKEN);
    String authToken = getCookieByName(request, AUTHN);

    boolean isValidState = !stateToken.isEmpty() && !authToken.isEmpty();

    if (isValidState) {
        return true;
    }

    else {
        return false;
    }
}

它两次调用 getCookieName(),它有这个实现。

public String getCookieByName(HttpServletRequest request, String cookieName) {
    try {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(cookieName)) {
                    return cookie.getValue();
                }
            }
        }
    } catch (Exception e) {
        ExceptionLogger.logDetailedError("CookieSessionUtils.getCookieByName", e);
        log.error("Error on Cookie " + e.getMessage());
    }
    return "";
}

然后我有这个用于我的测试:

@WebMvcTest(value = CookieSessionUtils.class, includeFilters =      
{@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {ApiOriginFilter.class})}) 
class CookieSessionUtilsTest {

@Autowired
private CookieSessionUtils cookieSessionUtils;

@Mock
private HttpServletRequest request;

@BeforeEach
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void testVerifyState() {

    Cookie mockCookie1 = Mockito.mock(Cookie.class);
    Cookie mockCookie2 = Mockito.mock(Cookie.class);
    when(mockCookie1.getName()).thenReturn("stateToken");
    when(mockCookie1.getValue()).thenReturn("stateToken");

    when(mockCookie2.getName()).thenReturn("authn");
    when(mockCookie2.getValue()).thenReturn("authn");

    when(request.getCookies()).thenReturn(new Cookie[]{mockCookie1, mockCookie2});
    
    when(cookieSessionUtils.getCookieByName(request, "stateToken")).thenReturn("stateToken");
    when(cookieSessionUtils.getCookieByName(request, "authn")).thenReturn("authn");
    
    assertTrue(cookieSessionUtils.verifyState(request));
}

然而,它总是失败返回 false 落入 return ""getCookieByName() 方法似乎被多次触发并且 getName() 和 getValue() 的值被覆盖其他 cookie,因此它在 (cookie.getName().equals(cookieName)) 上失败。不确定我做错了什么。

谢谢。

没必要这么复杂。对于模拟 servlet 的东西,您可以简单地使用 spring-test 提供的模拟实现。比Mockito用起来更方便

您可以简单地将测试用例编写为:

@Test
public void testVerifyState() {

    MockHttpServletRequest request = MockMvcRequestBuilders.get("/dummy")
            .cookie(new MockCookie("stateToken", "stateToken"))
            .cookie(new MockCookie("authn", "authn"))
            .buildRequest(new MockServletContext());

    assertTrue(cookieSessionUtils.verifyState(request));        
}

此外,如果您正在测试的 CookieSessionUtils 只是一个实用程序 class,它没有其他 spring bean 依赖项,您可以进一步简化您的测试,使其只是一个简单的JUnit 测试而不是 @WebMvcTest.

基于,以下两种方法均有效。这个问题实际上是非常微妙和微不足道的。 cookie 的值为“authn”,但其名称为“Authn”,因此由于大写,它们之间不匹配。

private static final String STATE_TOKEN = "stateToken";
private static final String AUTHN = "Authn";


@Test
public void testVerifyState1() {

    Cookie mockCookie1 = Mockito.mock(Cookie.class);
    Cookie mockCookie2 = Mockito.mock(Cookie.class);
    when(mockCookie1.getName()).thenReturn("stateToken");
    when(mockCookie1.getValue()).thenReturn("stateToken");

    when(mockCookie2.getName()).thenReturn("authn");
    when(mockCookie2.getValue()).thenReturn("Authn");

    when(request.getCookies()).thenReturn(new Cookie[]{mockCookie1, mockCookie2});

    when(cookieSessionUtils.getCookieByName(request, "stateToken")).thenReturn("stateToken");
    when(cookieSessionUtils.getCookieByName(request, "Authn")).thenReturn("Authn");

    assertTrue(cookieSessionUtils.verifyState(request, ""));
}


@Test
public void testVerifyState() {

    MockHttpServletRequest request = MockMvcRequestBuilders.get("/dummy")
            .cookie(new MockCookie("stateToken", "stateToken"))
            .cookie(new MockCookie("Authn", "authn"))
            .buildRequest(new MockServletContext());

    assertTrue(cookieSessionUtils.verifyState(request, ""));
}