Spring boot 空手道:如何使用YAML文件而不是application.properties来配置空手道模拟servlet?

Spring boot 空手道:如何使用YAML文件而不是application.properties来配置空手道模拟servlet?,spring-boot,yaml,config,karate,Spring Boot,Yaml,Config,Karate,我们有一个Spring引导项目,它使用application.yml文件为datasource、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);

我们有一个Spring引导项目,它使用application.yml文件为datasource、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;
}
模拟Spring MVC servlet类取自空手道模拟servlet演示github项目:

/**
 * @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);
    }

}
但是,在EnableAutoConfiguration注释上MockConfig.class失败:

@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上下文

您已经发现,
@PropertySource
仅支持属性文件

请看以下问题:


希望这能有所帮助。

我通过以下更改使application.yml文件得到Spring的尊重和加载:

  • 将YamlPropertySourceFactory util类添加到测试包:
  • Spring上下文负载和所有空手道测试都通过

    如果有更简单的方法使用空手道加载YAML文件作为Spring上下文,那么请发布它。就目前而言,这将起作用


    参考资料:

    我们能否就此答案进行总结请:
    
    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();
        }
    }