我们有一个Spring Boot项目,该项目使用application.yml文件为数据源,rabbitmq等内容配置spring上下文。
可以将YAML文件加载到karate-config.js中以获取baseUrl,并且工作正常。
function fn() {
var env = karate.env; // get system property 'karate.env'
karate.log('karate.env system property was:', env);
if (!env) {
env = 'dev';
}
karate.log('karate environment set to:', env);
var config = karate.read('classpath:application.yml');
karate.log('baseUrl configured for API tests: '+config.baseUrl)
if (env == 'dev') {
var Factory = Java.type('MockSpringMvcServlet');
karate.configure('httpClientInstance', Factory.getMock());
//var result = karate.callSingle('classpath:demo/headers/common-noheaders.feature', config);
} else if (env == 'stg') {
// customize
} else if (env == 'prod') {
// customize
}
return config;
}
从空手道模拟servlet演示github项目中获取的Mock Spring MVC servlet类:
/**
* @author pthomas3
*/
public class MockSpringMvcServlet extends MockHttpClient {
private final Servlet servlet;
private final ServletContext servletContext;
public MockSpringMvcServlet(Servlet servlet, ServletContext servletContext) {
this.servlet = servlet;
this.servletContext = servletContext;
}
@Override
protected Servlet getServlet(HttpRequestBuilder request) {
return servlet;
}
@Override
protected ServletContext getServletContext() {
return servletContext;
}
private static final ServletContext SERVLET_CONTEXT = new MockServletContext();
private static final Servlet SERVLET;
static {
SERVLET = initServlet();
}
private static Servlet initServlet() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MockConfig.class);
context.setServletContext(SERVLET_CONTEXT);
DispatcherServlet servlet = new DispatcherServlet(context);
ServletConfig servletConfig = new MockServletConfig();
try {
servlet.init(servletConfig);
} catch (Exception e) {
throw new RuntimeException(e);
}
return servlet;
}
public static MockSpringMvcServlet getMock() {
return new MockSpringMvcServlet(SERVLET, SERVLET_CONTEXT);
}
}
但是,MockConfig.class在EnableAutoConfiguration批注上失败:
@Configuration
@EnableAutoConfiguration
// @PropertySource("classpath:application.yml") // only for key/value pair .properties files and not YAML
public class MockConfig {
// Global Exception Handler ...
// Services ...
// Controllers ...
@Bean
public NumbersAPI numbersAPI() {
return new NumbersAPI();
}
}
例外是:
2019-04-23 15:13:21.297 INFO --- [ main] com.intuit.karate : karate.env system property was: null
2019-04-23 15:13:21.306 INFO --- [ main] com.intuit.karate : karate environment set to: dev
2019-04-23 15:13:21.429 INFO --- [ main] com.intuit.karate : baseUrl configured for API tests: http://localhost:50000
2019-04-23 15:13:21.469 INFO --- [ main] o.s.mock.web.MockServletContext : Initializing Spring FrameworkServlet ''
2019-04-23 15:13:21.469 INFO --- [ main] o.s.web.servlet.DispatcherServlet : FrameworkServlet '': initialization started
2019-04-23 15:13:21.496 INFO --- [ main] .s.AnnotationConfigWebApplicationContext : Refreshing WebApplicationContext for namespace '-servlet': startup date [Tue Apr 23 15:13:21 EDT 2019]; root of context hierarchy
2019-04-23 15:13:21.535 INFO --- [ main] .s.AnnotationConfigWebApplicationContext : Registering annotated classes: [class MockConfig]
2019-04-23 15:13:22.215 INFO --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Dbcp2; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Dbcp2.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]]
2019-04-23 15:13:22.330 WARN --- [ main] o.s.b.a.AutoConfigurationPackages : @EnableAutoConfiguration was declared on a class in the default package. Automatic @Repository and @Entity scanning is not enabled.
2019-04-23 15:13:22.714 INFO --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration' of type [org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration$$EnhancerBySpringCGLIB$$cafe2407] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-04-23 15:13:23.212 WARN --- [ main] .s.AnnotationConfigWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
2019-04-23 15:13:23.215 ERROR --- [ main] o.s.web.servlet.DispatcherServlet : Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
我已经使用空手道模拟servlet github项目的文档作为指导来使其他空手道测试成功工作,但是我不知道如何使用应用程序YAML文件为空手道测试配置spring上下文。
答案 0 :(得分:1)
答案 1 :(得分:0)
通过进行以下更改,我能够使Spring尊重并加载application.yml文件:
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
String sourceName = name != null ? name : resource.getResource().getFilename();
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
} catch (IllegalStateException e) {
// for ignoreResourceNotFound
Throwable cause = e.getCause();
if (cause instanceof FileNotFoundException)
throw (FileNotFoundException) e.getCause();
throw e;
}
}
}
和
@Configuration
@EnableAutoConfiguration
@PropertySource(factory = YamlPropertySourceFactory.class, value = "classpath:application.yml")
public class MockConfig {
// Global Exception Handler ...
@Bean
public ExampleAPIExceptionHandler exampleAPIExceptionHandler() {
return new ExampleAPIExceptionHandler();
}
// Services ...
// Controllers ...
@Bean
public NumbersAPI numbersAPI() {
return new NumbersAPI();
}
}
Spring上下文加载并且所有空手道测试通过。
如果有一种使用空手道将YAML文件作为Spring上下文加载的简单方法,请发布该文件。目前,这将起作用。