How do I unit test a Servlet Filter with jUnit? ServletRequest, ServletResponse, FilterChain

huangapple go评论97阅读模式
英文:

How do I unit test a Servlet Filter with jUnit? ServletRequest, ServletResponse, FilterChain

问题

@SlingFilter(order = -700, scope = SlingFilterScope.REQUEST)
public class LoggingFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
            final FilterChain filterChain) throws IOException, ServletException {

        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
        logger.debug("request for {}, with selector {}", slingRequest
                .getRequestPathInfo().getResourcePath(), slingRequest
                .getRequestPathInfo().getSelectorString());

        filterChain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}

}
英文:

How to properly cover Filter with JUnit?

@SlingFilter(order = -700, scope = SlingFilterScope.REQUEST)
public class LoggingFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
            final FilterChain filterChain) throws IOException, ServletException {

        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
        logger.debug("request for {}, with selector {}", slingRequest
                .getRequestPathInfo().getResourcePath(), slingRequest
                .getRequestPathInfo().getSelectorString());

        filterChain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}

}

答案1

得分: 4

@ExtendWith(MockitoExtension.class)
public class LoggingFilterTest {

    @InjectMocks
    private LoggingFilter loggingFilter;

    @Mock
    private ServletRequest request;

    @Mock
    private ServletResponse response;

    @Mock
    private FilterChain filterChain;

    @Mock
    private RequestPathInfo requestPathInfo;

    @Test
    public void testDoFilter() throws IOException, ServletException {

        Mockito.when(request.getResourcePath()).thenReturn(requestPathInfo);
        Mockito.when(requestPathInfo.getResourcePath()).thenReturn("/testPath", "selectorString");
        Mockito.doNothing().when(filterChain).doFilter(Mockito.eq(request), Mockito.eq(response));

        loggingFilter.doFilter(request, response, filterChain);

        Mockito.verify(filterChain, times(1)).doFilter(Mockito.eq(request), Mockito.eq(response));
    }
}

If you are using junit4, then change @ExtendWith(MockitoExtension.class) to @RunWith(MockitoJUnitRunner.class).


<details>
<summary>英文:</summary>

You can use below code for your testing with `Junit-5`

@ExtendWith(MockitoExtension.class)
public class LoggingFilterTest{

@InjectMocks
private LoggingFilter loggingFilter;

@Mock
private ServletRequest request

@Mock
private ServletResponse response

@Mock
private FilterChain filterChain

@Mock
private RequestPathInfo requestPathInfo;

@Test
public void testDoFilter() throws IOException, ServletException{

	Mockito.when(request.getResourcePath()).thenReturn(requestPathInfo);
	Mockito.when(requestPathInfo.getResourcePath()).thenReturn(&quot;/testPath&quot;, &quot;selectorString&quot;);
	Mockito.doNothing().when(filterChain).doFilter(Mockito.eq(request),	Mockito.eq(response));
	
	loggingFilter.doFilter(request, response, filterChain);
	
	Mockito.verify(filterChain, times(1)).doFilter(Mockito.eq(request),	Mockito.eq(response));
}

}


If you are using `junit4` then change `@ExtendWith(MockitoExtension.class)` to `@RunWith(MockitoJUnitRunner.class)`

</details>



# 答案2
**得分**: 3

调用 doFilter,将模拟的 ServletRequest、ServletResponse 和 FilterChain 作为其参数传递。

```java
@Test
public void testDoFilter() {
    LoggingFilter filterUnderTest = new LoggingFilter();    
    MockFilterChain mockChain = new MockFilterChain();
    MockServletRequest req = new MockServletRequest("/test.jsp");
    MockServletResponse rsp = new MockServletResponse();

    filterUnderTest.doFilter(req, rsp, mockChain);

    assertEquals("/test.jsp", rsp.getLastRedirect());
}

在实际应用中,您会希望将设置移到 @Before setUp() 方法中,并编写更多的 @Test 方法来覆盖每个可能的执行路径。

您可能会使用模拟框架,比如 JMockMockito 来创建模拟,而不是我在这里使用的假设的 MockModeService 等。这是单元测试的方法,而不是集成测试。您只测试正在测试的单元(以及测试代码)。

英文:

Invoke doFilter passing the mock ServletRequest, ServletResponse and FilterChain as its parameters.

@Test
public void testDoFilter() {
    LoggingFilter filterUnderTest = new LoggingFilter();    
    MockFilterChain mockChain = new MockFilterChain();
    MockServletRequest req = new MockServletRequest(&quot;/test.jsp&quot;);
    MockServletResponse rsp = new MockServletResponse();

    filterUnderTest.doFilter(req, rsp, mockChain);

    assertEquals(&quot;/test.jsp&quot;,rsp.getLastRedirect());
}

In practice, you'll want to move the setup into an @Before setUp() method, and write more @Test methods to cover every possible execution path.

And you'd probably use a mocking framework like JMock or Mockito to create mocks, rather than the hypothetical MockModeService etc. I've used here.

This is a unit testing approach, as opposed to an integration test. You are only exercising the unit under test (and the test code).

答案3

得分: 1

如果您在JUnit 5中使用AEM Mocks,代码可能如下所示:

@ExtendWith(AemContextExtension.class)
class SimpleFilterTest {

    private static final AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);

    private static final String RESOURCE_PATH = "/content/test";
    private static final String SELECTOR_STRING = "selectors";

    private static SimpleFilter simpleFilter;
    private static FilterChain filterChain;

    @BeforeAll
    static void setup() {
        simpleFilter = context.registerService(SimpleFilter.class, new SimpleFilter());
        filterChain = context.registerService(FilterChain.class, new MockFilterChain());
    }

    @Test
    @DisplayName("GIVEN the request, WHEN is executed, THEN request should be filtered and contain corresponding header")
    void testDoFilter() throws ServletException, IOException {
        context.requestPathInfo().setResourcePath(RESOURCE_PATH);
        context.requestPathInfo().setSelectorString(SELECTOR_STRING);

        simpleFilter.doFilter(context.request(), context.response(), filterChain);

        assertEquals("true", context.response().getHeader("filtered"));
    }

}

Mock

public class MockFilterChain implements FilterChain {

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException, ServletException {
        // do nothing
    }

}

一些简单的过滤器

@Component(service = Filter.class)
@SlingServletFilter(scope = SlingServletFilterScope.REQUEST)
@ServiceRanking(-700)
public class SimpleFilter implements Filter {

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
        log.debug("request for {}, with selector {}", slingRequest.getRequestPathInfo().getResourcePath(),
          slingRequest.getRequestPathInfo().getSelectorString());

        final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
        slingResponse.setHeader("filtered", "true");
        filterChain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }

}
英文:

If you use AEM Mocks with Junit5, then it could look something like this.

@ExtendWith(AemContextExtension.class)
class SimpleFilterTest {

    private static final AemContext context =  new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);

    private static final String RESOURCE_PATH = &quot;/content/test&quot;;
    private static final String SELECTOR_STRING = &quot;selectors&quot;;

    private static SimpleFilter simpleFilter;
    private static FilterChain filterChain;

    @BeforeAll
    static void setup() {
        simpleFilter = context.registerService(SimpleFilter.class, new SimpleFilter());
        filterChain = context.registerService(FilterChain.class, new MockFilterChain());
    }

    @Test
    @DisplayName(&quot;GIVEN the request, WHEN is executed, THEN request should be filtered and contain corresponding header&quot;)
    void testDoFilter() throws ServletException, IOException {
        context.requestPathInfo().setResourcePath(RESOURCE_PATH);
        context.requestPathInfo().setSelectorString(SELECTOR_STRING);

        simpleFilter.doFilter(context.request(), context.response(), filterChain);

        assertEquals(&quot;true&quot;, context.response().getHeader(&quot;filtered&quot;));
    }

}

Mock

public class MockFilterChain implements FilterChain {

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException, ServletException {
        // do nothing
    }

}

Some simple filter

@Component(service = Filter.class)
@SlingServletFilter(scope = SlingServletFilterScope.REQUEST)
@ServiceRanking(-700)
public class SimpleFilter implements Filter {

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
        log.debug(&quot;request for {}, with selector {}&quot;, slingRequest.getRequestPathInfo().getResourcePath(),
          slingRequest.getRequestPathInfo().getSelectorString());

        final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
        slingResponse.setHeader(&quot;filtered&quot;, &quot;true&quot;);
        filterChain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }

}

huangapple
  • 本文由 发表于 2020年9月2日 21:07:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/63706202.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定