Java SpringMVC:使用TestWebApplicationContext和嵌入式Jetty进行UI测试
tldr如何从嵌入式jetty中的WebApplicationContext部署一个简单的自动测试用例 我所拥有的: 一个spring应用程序(不是SpringBoot),它使用注释配置(没有web.xml)并为生产构建(使用gradle)到ear并部署在wildfly上 我最终想要做的是: 具有自包含(在应用程序测试包中)的ui测试,可以像其他单元或集成测试一样轻松执行(无需构建和部署) 到目前为止我所做的:Java SpringMVC:使用TestWebApplicationContext和嵌入式Jetty进行UI测试,java,spring,spring-mvc,selenium-webdriver,embedded-jetty,Java,Spring,Spring Mvc,Selenium Webdriver,Embedded Jetty,tldr如何从嵌入式jetty中的WebApplicationContext部署一个简单的自动测试用例 我所拥有的: 一个spring应用程序(不是SpringBoot),它使用注释配置(没有web.xml)并为生产构建(使用gradle)到ear并部署在wildfly上 我最终想要做的是: 具有自包含(在应用程序测试包中)的ui测试,可以像其他单元或集成测试一样轻松执行(无需构建和部署) 到目前为止我所做的: 简单的部分:使用SeleniumWebDriver设置实际测试 困难的部分:使用测
- 简单的部分:使用SeleniumWebDriver设置实际测试
- 困难的部分:使用测试WebApplicationContext启动嵌入式Jetty
- 控制器在请求时被命中
- Spring Security处于活动状态
- 找到并呈现JSP(感谢)
- 缺少所有其他静态资源(css、js、图像等)。基本上从主题到主题的所有内容
ResourceHandler使用哪种情况并不重要。两者都不起作用。主题文件在哪里?(希望在
src/website/application.war
)被引用。您可能希望在问题中描述如何配置mvc资源。-请看:我已编辑了我的问题。希望这是你感兴趣的。谢谢你看。谢谢,这是一个信息丰富得多的问题。可悲的是,我不能帮助春季方面,因为我的专业知识是在码头。但希望春天那边的人能帮上忙。(我将调整标签,使其成为更受欢迎的标签)
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.jsp.JettyJspServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class JettyServerFactory {
private Server server = null;
public Server start(WebApplicationContext context) throws Exception {
if (server == null) {
this.server = new Server(9090);
setupServer(context);
server.start();
//server.join();
}
return server;
}
public void stop() throws Exception {
if (server != null) {
server.stop();
}
}
private void setupServer(WebApplicationContext context) throws Exception {
final ServletContextHandler contextHandler = new ServletContextHandler();
// Since this is a ServletContextHandler we must manually configure JSP support.
enableEmbeddedJspSupport(contextHandler);
// Spring Security
enableSpringSecurity(contextHandler, context);
/*
// TODO: Does not seem to have any effect
// Set reference to actual Spring ApplicationContext
ServletContext servletContext = contextHandler.getServletContext();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
*/
// Set resource base folder
contextHandler.setBaseResource(getResourceBase());
// Add DispatcherServlet to context
final ServletHolder servletHolder = new ServletHolder("default", new DispatcherServlet(context));
servletHolder.setInitParameter("dirAllowed", "true");
contextHandler.setContextPath("/oauth");
contextHandler.addServlet(servletHolder, "/");
// Add context to server
server.setHandler(contextHandler);
}
private Resource getResourceBase() {
File file = new File("src/website/application.war");
//servletHolder.setInitParameter("resourceBase", getWebRootResourceUri().toASCIIString());
final Resource base = Resource.newResource(file);
return base;
}
/**
* Apply existing securityFilterChain to context
*
* @param contextHandler
* @param context
*/
private void enableSpringSecurity(ServletContextHandler contextHandler, WebApplicationContext context) {
FilterChainProxy filter = (FilterChainProxy) context.getBean("springSecurityFilterChain");
FilterHolder filterHolder = new FilterHolder(filter);
contextHandler.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class));
server.setSessionIdManager(new HashSessionIdManager());
HashSessionManager manager = new HashSessionManager();
SessionHandler sessions = new SessionHandler(manager);
contextHandler.setHandler(sessions);
}
/**
* Setup JSP Support for ServletContextHandlers.
* <p>
* NOTE: This is not required or appropriate if using a WebAppContext.
* </p>
*
* @param servletContextHandler the ServletContextHandler to configure
* @throws IOException if unable to configure
*/
private void enableEmbeddedJspSupport(ServletContextHandler servletContextHandler) throws IOException {
// Establish Scratch directory for the servlet context (used by JSP compilation)
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp");
if (!scratchDir.exists()) {
if (!scratchDir.mkdirs()) {
throw new IOException("Unable to create scratch directory: " + scratchDir);
}
}
servletContextHandler.setAttribute("javax.servlet.context.tempdir", scratchDir);
// Set Classloader of Context to be sane (needed for JSTL)
// JSP requires a non-System classloader, this simply wraps the
// embedded System classloader in a way that makes it suitable
// for JSP to use
ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
servletContextHandler.setClassLoader(jspClassLoader);
// Manually call JettyJasperInitializer on context startup
servletContextHandler.addBean(new JspStarter(servletContextHandler));
// Create / Register JSP Servlet (must be named "jsp" per spec)
ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
holderJsp.setInitOrder(0);
holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
holderJsp.setInitParameter("fork", "false");
holderJsp.setInitParameter("xpoweredBy", "false");
holderJsp.setInitParameter("compilerTargetVM", "1.8");
holderJsp.setInitParameter("compilerSourceVM", "1.8");
holderJsp.setInitParameter("keepgenerated", "true");
servletContextHandler.addServlet(holderJsp, "*.jsp");
}
/**
* JspStarter for embedded ServletContextHandlers
*
* This is added as a bean that is a jetty LifeCycle on the ServletContextHandler. This bean's doStart method will
* be called as the ServletContextHandler starts, and will call the ServletContainerInitializer for the jsp engine.
*
*/
public static class JspStarter extends AbstractLifeCycle
implements ServletContextHandler.ServletContainerInitializerCaller {
JettyJasperInitializer sci;
ServletContextHandler context;
public JspStarter(ServletContextHandler context) {
this.sci = new JettyJasperInitializer();
this.context = context;
this.context.setAttribute("org.apache.tomcat.JarScanner", new StandardJarScanner());
}
@Override
protected void doStart() throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
try {
sci.onStartup(null, context.getServletContext());
super.doStart();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
}
private URI getWebRootResourceUri() throws FileNotFoundException, URISyntaxException, MalformedURLException {
String WEBROOT_INDEX = "/application.war/";
URL indexUri = this.getClass().getResource(WEBROOT_INDEX);
if (indexUri == null) {
throw new FileNotFoundException("Unable to find resource " + WEBROOT_INDEX);
}
File file = new File("src/website/application.war");
System.out.println(indexUri.toURI());
System.out.println(file.toURI());
System.out.println(file.getAbsolutePath());
return file.toURI();
}
}
...
@WebAppConfiguration
public class ATestClass {
@Autowired
WebApplicationContext context;
...
@Before
public void setupTest() throws Exception {
new JettyServerFactory().start(context);
...
}
...
...
@EnableWebMvc
@Configuration
public class AppWebMvcConfiguration implements WebMvcConfigurer {
...
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
boolean developmentMode = configuration.getBooleanFromNewconfig(false, "oauth2.developmentMode");
if (USE_VERSIONED_RESOURCES) {
registry.addResourceHandler("/themes/**")
.addResourceLocations("/themes/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(developmentMode ? false : true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
} else {
registry.addResourceHandler("/themes/**")
.addResourceLocations("/themes/")
.setCacheControl(CacheControl.noCache());
}
}
...
}