Огурец в основной области Spring Boot: Autowire не работает - PullRequest
4 голосов
/ 05 августа 2020

Работа над этим сообщением: Cucumber: бэкэнд не обнаружен при запуске из Spring Boot jar
Я пытаюсь заставить Cucumber полноценно работать в живом приложении Spring Boot. В настоящее время у меня есть приложение PO C, использующее вышеупомянутый пост-код для создания среды выполнения Cucumber, и оно запускает простой класс Feature / Steps со ссылкой на Bean:
Service:

public void testFeature(){
        RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList<String>(asList("--glue", "org.bdd.poc", "--no-dry-run", "--monochrome", "classpath:features")));
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        ResourceLoader resourceLoader = new CustomMultiLoader(classLoader);
        ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
        Runtime runtime = new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
        try {
            runtime.run();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

DemoSteps:

(no class annotation)
public class DemoSteps {

    @Autowired
    private MyBean bean;

    public DemoSteps(){
        System.err.println("STEP INIT");
    }

    @Given("a proof of concept")
    public void givenAPOC(){

    }

    @When("doing a demo")
    public void whenDemo(){

    }

    @Then("it should talk to a bean")
    public void thenItShouldTalkToABean(){
        this.bean.poke();
    }
}

Bean:

@Component
public class MyBean {
    public void poke(){
        System.err.println("I'VE BEEN POKED! THE PAIN!");
    }
}

Класс DemoSteps. java имеет это как поле класса с @Autowired на месте, но пока он не заполняет ссылку на bean-компонент и не завершает работу после Конструкция DemoSteps. В процессе отладки я вижу, что для создания экземпляра Steps используются фабрики Spring bean-компонентов, но ничего, касающееся автоматического подключения, не затрагивается. Я предполагаю, что для того, чтобы применить какое-то соединение к основному SpringContext, находится либо:

  • Соответствующая реализация Backend
  • Соответствующая реализация Glue

I знаю, что нечто подобное могло быть выполнено с использованием инфраструктуры Karate, но я не нашел, что позволяет этому установить соединение. boot-maven-plugin "config.

1 Ответ

0 голосов
/ 09 августа 2020

Решение, которое у меня было, было не совсем Backend, но его частью. Зависимость cucumber-spring имеет реализацию cucumber.api.java.ObjectFactory. Этот класс действует как точка доступа для создания классов Step, содержащих @Given / @When / et c. Есть «тестовый класс», который поддерживает это. Однако я пошел другим путем создания «дочернего» контекста приложения по сравнению с основным, AnnotationApplicationContext, в частности, для обработки аннотаций @Autowired. В любом случае, вот код для этого:
Сервис:

Service Method:
    @Autowired(required = false)
    private List<LiveTestEventHandler> testEventHandlerList;
    @Autowired
    private ApplicationContext applicationContext;

    public void testFeature(){
        RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList<String>(asList("--glue", "org.bddynamic.poc", "--no-dry-run", "--monochrome", "classpath:features")));
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        ResourceLoader resourceLoader = new CustomMultiLoader(classLoader);
        ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
        ObjectFactory objectFactory = new LiveTestFactory(this.applicationContext);
        JavaBackend javaBackend = new JavaBackend(objectFactory,classFinder);
        Runtime runtime = new Runtime(resourceLoader, classLoader, asList(javaBackend), runtimeOptions);
        for(LiveTestEventHandler handler : this.testEventHandlerList){
            runtime.getEventBus().registerHandlerFor(handler.getSupportedClass(),handler);
        }
        try {
            runtime.run();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Custom Factory:

(действительно урезанная версия cucumber-spring:runtime.java.spring.SpringFactory.java)

public class LiveTestFactory implements ObjectFactory {
    private final DefaultListableBeanFactory beanFactory;
    private final GenericApplicationContext applicationContext;
    private final Collection<Class<?>> stepClasses = new HashSet();
    public LiveTestFactory(ApplicationContext applicationContext){
        AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
        childContext.setParent(applicationContext);
        this.applicationContext = childContext;
        this.beanFactory = (DefaultListableBeanFactory) this.applicationContext.getBeanFactory();
    }
    @Override
    public void start() {
        ((ConfigurableApplicationContext)this.applicationContext).registerShutdownHook();
        beanFactory.registerScope(LiveTestScope.NAME, new LiveTestScope());
        for(Class stepClass : this.stepClasses){
            this.registerStepClassBeanDefinition(this.beanFactory, stepClass);
        }
        this.applicationContext.refresh();
        this.applicationContext.start();
    }
    @Override
    public void stop() {
        LiveCodeContext.getInstance().stop();
        this.applicationContext.stop();
    }
    @Override
    public boolean addClass(Class<?> stepClass) {
        if (!this.stepClasses.contains(stepClass)) {
            this.stepClasses.add(stepClass);
        }
        return true;
    }
    @Override
    public <T> T getInstance(Class<T> type) {
        try {
            return this.applicationContext.getBean(type);
        } catch (BeansException var3) {
            throw new CucumberException(var3.getMessage(), var3);
        }
    }
    private void registerStepClassBeanDefinition(DefaultListableBeanFactory beanFactory, Class<?> stepClass) {
        BeanDefinitionRegistry registry = beanFactory;
        BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(stepClass).setScope(LiveTestScope.NAME).getBeanDefinition();
        registry.registerBeanDefinition(stepClass.getName(), beanDefinition);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...