Spring 启动测试过滤器
Spring Boot test Filter
注意:下面的错误实际上是由过滤器中的拼写错误引起的,请参阅@jccampanero 在他下面的回答中提到的
我一直在尝试几种不同的方法来测试过滤器,但是我不断遇到一个或另一个错误,所以我希望能找到一些方向。
这是一个应该只进行重定向的虚拟过滤器。
package org.example.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) req;
chain.sendRedirect("/splash");
}
}
还有一个基本的 Spring 启动应用程序 class:
package org.example;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ApplicationClass {
}
我想我只是不清楚 'level' 的 Spring 引导测试我正在尝试做什么,这是我做过的一些尝试和错误:
选项 1. 尝试模拟,例如 here
package org.example.filters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import org.junit.jupiter.api.Test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
public class LocaleFilterIntegrationTestStandalone {
@Test
public void whenNoLocaleRedirectToSplash() throws Exception {
standaloneSetup(new TestController()).addFilters(new RedirectFilter()).build().perform(get("/"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/splash"));
}
@Controller
private static class TestController {
@GetMapping("/")
public String get() {
return "got it";
}
}
}
错误:java.lang.ClassCastException: class org.springframework.mock.web.MockHttpServletRequest cannot be cast to class javax.servlet.http.HttpServletResponse
选项2,尝试使用@WebMvcTest
,与选项1
有同样的问题
package org.example.filters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping;
@WebMvcTest
public class LocaleFilterIntegrationTestWebMvc {
@Autowired
private MockMvc mvc;
@Test
public void noLanguageShouldRedirectToSplash() throws Exception {
mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("/splash"));
}
@Controller
private static class TestController {
@GetMapping("/")
public String get() {
return "got it";
}
}
}
错误:java.lang.ClassCastException: class org.springframework.mock.web.MockHttpServletRequest cannot be cast to class javax.servlet.http.HttpServletResponse
选项 3,尝试启动整个上下文,我认为它需要能够转换为 HttpServletRequest
:
package org.example.filters;
import java.net.URI;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class LocaleFilterIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void noLanguageShouldRedirectToSplash() throws Exception {
URI uri = new URI("http", "localhost:" + port, "/", null, null);
String result = restTemplate.getForObject(uri.toString(), String.class);
// not sure how, but test for redirect...
}
@Controller
private static class TestController {
@GetMapping("/")
public String get() {
return "got it";
}
}
}
错误:class org.apache.catalina.connector.RequestFacade cannot be cast to class javax.servlet.http.HttpServletResponse
选项 4,@m-deinem 建议
package org.example.filters;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
public class LocaleFilterIntegrationTestPlain {
private final RedirectFilter redirectFilter = new RedirectFilter();
@Test
public void noLanguageShouldRedirectToSplash() throws Exception {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
redirectFilter.doFilter(req, res, chain);
}
}
错误:java.lang.ClassCastException: class org.springframework.mock.web.MockHttpServletRequest cannot be cast to class javax.servlet.http.HttpServletResponse
首先,您的 RedirectFilter
包含一个错误,它试图将传入的 HttpServletRequest
转换为 HttpServletResponse
,因为您使用了错误的变量。
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
res.sendRedirect("/splash");
}
}
这两行都使用 req
而后者应该使用 res
(这也是异常字面上告诉你的)。
接下来只需编写一个简单的单元测试,您尝试编写集成测试会使事情变得过于复杂。
public class RedirectFilterTest
private final RedirectFilter filter = new RedirectFilter();
@Test
public void redirectTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
filter.doFilter(req, res, chain);
assertEquals("/splash", res.getRedirectedUrl());
}
拜托,也许这只是一个错字,但请注意,在您的 RedirectFilter
doFilter
方法中,您错误地将变量 req
转换为 HttpServletResponse
:
package org.example.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
// Please, note the incorrect cast
HttpServletResponse response = (HttpServletResponse) req;
chain.sendRedirect("/splash");
}
}
相反,它应该是:
package org.example.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
chain.sendRedirect("/splash");
}
}
这很可能是 ClassCastException
和测试失败的原因。
已解决,@M提出的方案。 Deinum 是一个非常好的和直接的。
注意:下面的错误实际上是由过滤器中的拼写错误引起的,请参阅@jccampanero 在他下面的回答中提到的
我一直在尝试几种不同的方法来测试过滤器,但是我不断遇到一个或另一个错误,所以我希望能找到一些方向。
这是一个应该只进行重定向的虚拟过滤器。
package org.example.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) req;
chain.sendRedirect("/splash");
}
}
还有一个基本的 Spring 启动应用程序 class:
package org.example;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ApplicationClass {
}
我想我只是不清楚 'level' 的 Spring 引导测试我正在尝试做什么,这是我做过的一些尝试和错误:
选项 1. 尝试模拟,例如 here
package org.example.filters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import org.junit.jupiter.api.Test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
public class LocaleFilterIntegrationTestStandalone {
@Test
public void whenNoLocaleRedirectToSplash() throws Exception {
standaloneSetup(new TestController()).addFilters(new RedirectFilter()).build().perform(get("/"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/splash"));
}
@Controller
private static class TestController {
@GetMapping("/")
public String get() {
return "got it";
}
}
}
错误:java.lang.ClassCastException: class org.springframework.mock.web.MockHttpServletRequest cannot be cast to class javax.servlet.http.HttpServletResponse
选项2,尝试使用@WebMvcTest
,与选项1
package org.example.filters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping;
@WebMvcTest
public class LocaleFilterIntegrationTestWebMvc {
@Autowired
private MockMvc mvc;
@Test
public void noLanguageShouldRedirectToSplash() throws Exception {
mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("/splash"));
}
@Controller
private static class TestController {
@GetMapping("/")
public String get() {
return "got it";
}
}
}
错误:java.lang.ClassCastException: class org.springframework.mock.web.MockHttpServletRequest cannot be cast to class javax.servlet.http.HttpServletResponse
选项 3,尝试启动整个上下文,我认为它需要能够转换为 HttpServletRequest
:
package org.example.filters;
import java.net.URI;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class LocaleFilterIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void noLanguageShouldRedirectToSplash() throws Exception {
URI uri = new URI("http", "localhost:" + port, "/", null, null);
String result = restTemplate.getForObject(uri.toString(), String.class);
// not sure how, but test for redirect...
}
@Controller
private static class TestController {
@GetMapping("/")
public String get() {
return "got it";
}
}
}
错误:class org.apache.catalina.connector.RequestFacade cannot be cast to class javax.servlet.http.HttpServletResponse
选项 4,@m-deinem 建议
package org.example.filters;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
public class LocaleFilterIntegrationTestPlain {
private final RedirectFilter redirectFilter = new RedirectFilter();
@Test
public void noLanguageShouldRedirectToSplash() throws Exception {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
redirectFilter.doFilter(req, res, chain);
}
}
错误:java.lang.ClassCastException: class org.springframework.mock.web.MockHttpServletRequest cannot be cast to class javax.servlet.http.HttpServletResponse
首先,您的 RedirectFilter
包含一个错误,它试图将传入的 HttpServletRequest
转换为 HttpServletResponse
,因为您使用了错误的变量。
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
res.sendRedirect("/splash");
}
}
这两行都使用 req
而后者应该使用 res
(这也是异常字面上告诉你的)。
接下来只需编写一个简单的单元测试,您尝试编写集成测试会使事情变得过于复杂。
public class RedirectFilterTest
private final RedirectFilter filter = new RedirectFilter();
@Test
public void redirectTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
filter.doFilter(req, res, chain);
assertEquals("/splash", res.getRedirectedUrl());
}
拜托,也许这只是一个错字,但请注意,在您的 RedirectFilter
doFilter
方法中,您错误地将变量 req
转换为 HttpServletResponse
:
package org.example.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
// Please, note the incorrect cast
HttpServletResponse response = (HttpServletResponse) req;
chain.sendRedirect("/splash");
}
}
相反,它应该是:
package org.example.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class RedirectFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
chain.sendRedirect("/splash");
}
}
这很可能是 ClassCastException
和测试失败的原因。
已解决,@M提出的方案。 Deinum 是一个非常好的和直接的。