首页 > 解决方案 > Injectmocks 无法实例化,因为没有找到线程绑定请求

问题描述

我正在尝试在 REST API 中创建一个日志记录实用程序,并且我需要来自 HttpServletRequest 的一些详细信息。

以下是日志记录实用程序的代码:

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import lombok.Getter;
import lombok.Setter;

@Component
@Scope(scopeName = "session",proxyMode = ScopedProxyMode.TARGET_CLASS)
@Getter
@Setter
public class LoggingUtil {

    private String uri;
    private String callerIp;
    private String authorization;

    public LoggingUtil() {
        HttpServletRequest httpServletRequest = 
                ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
        this.uri = httpServletRequest.getRequestURI();
        this.callerIp = httpServletRequest.getRemoteAddr();
        this.authorization = httpServletRequest.getHeader("Authorization");
    }

    public void log() {
        System.out.println("URI is "+this.uri+" Caller IP is "+this.callerIp+"authorization id is "+this.authorization);
    }
}

我正在尝试使用 JUnit-Mockito 框架对类进行单元测试,但测试覆盖率总是存在 InjectMocks 无法正常工作的问题。

以下是单元测试用例代码:

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;

import javax.servlet.http.HttpServletRequest;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.omg.CORBA.portable.ResponseHandler;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.context.request.RequestContextHolder;

@RunWith(SpringJUnit4ClassRunner.class)
public class LoggingUtilTest {

    @InjectMocks
    LoggingUtil loggingUtil;

    @Mock
    static HttpServletRequest httpServletRequest;

    @Mock
    static MockHttpServletRequest request = new MockHttpServletRequest();

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        httpServletRequest = mock(HttpServletRequest.class);
        request.setServerName("www.example.com");
        request.setRequestURI("/foo");
        request.setQueryString("param1=value1&param");
    }

    @Test
    public final void testLoggingUtil() {
        assertEquals(request.getRequestURI(),"/foo");
    }

}

以下是控制台中显示的错误:

org.mockito.exceptions.misusing.InjectMocksException: 
Cannot instantiate @InjectMocks field named 'loggingUtil' of type 'class in.name.util.LoggingUtil'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

    at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.initMocks(MockitoTestExecutionListener.java:68)
    at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.prepareTestInstance(MockitoTestExecutionListener.java:53)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
    at in.name.util.LoggingUtil.<init>(LoggingUtil.java:27)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.mockito.internal.util.reflection.FieldInitializer$NoArgConstructorInstantiator.instantiate(FieldInitializer.java:195)
    at org.mockito.internal.util.reflection.FieldInitializer.acquireFieldInstance(FieldInitializer.java:137)
    at org.mockito.internal.util.reflection.FieldInitializer.initialize(FieldInitializer.java:91)
    at org.mockito.internal.configuration.injection.PropertyAndSetterInjection.initializeInjectMocksField(PropertyAndSetterInjection.java:94)
    at org.mockito.internal.configuration.injection.PropertyAndSetterInjection.processInjection(PropertyAndSetterInjection.java:79)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:68)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.relayProcessToNextStrategy(MockInjectionStrategy.java:89)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:71)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.relayProcessToNextStrategy(MockInjectionStrategy.java:89)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:71)
    at org.mockito.internal.configuration.injection.MockInjection$OngoingMockInjection.apply(MockInjection.java:92)
    at org.mockito.internal.configuration.DefaultInjectionEngine.injectMocksOnFields(DefaultInjectionEngine.java:25)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.injectMocks(InjectingAnnotationEngine.java:87)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.processInjectMocks(InjectingAnnotationEngine.java:48)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:42)
    at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:69)
    ... 25 more

标签: javaspringspring-bootunit-testingjunit

解决方案


我想提出以下测试。希望这可以帮助:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@RunWith(SpringJUnit4ClassRunner.class)
public class LoggingUtilTest {
    private LoggingUtil loggingUtil;

    private MockHttpServletRequest request = new MockHttpServletRequest();

    @Before
    public void setUpBeforeClass() throws Exception {
        request.setRequestURI("/foo");
        request.setRemoteAddr("10.1.1.11");
        request.addHeader("Authorization", "xAuth");
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
        loggingUtil = new LoggingUtil();
    }

    @Test
    public final void testLoggingUtil() {
        String requestURI = ReflectionTestUtils.getField(loggingUtil, "uri").toString();
        assertEquals(requestURI,"/foo");

        String authorization = ReflectionTestUtils.getField(loggingUtil, "authorization").toString();
        assertEquals(authorization,"xAuth");

        String callerIp = ReflectionTestUtils.getField(loggingUtil, "callerIp").toString();
        assertEquals(callerIp,"10.1.1.11");
    }
}

推荐阅读