当前位置: 首页 > 知识库问答 >
问题:

带Guice的cucumber-多Guice注射器

陈斌
2023-03-14

我使用< code>Cucumber和< code>Guice作为DI。我遇到了以下问题:我有一个步骤,即

class MyStep() {

    @Inject
    private MyService myService;

    @Given("Some acction happen")
    public void sthHappen() {
        myService.doSth();
    }
}

我让这个类作为JUnit测试运行它

@RunWith(Cucumber.class)
@CucumberOptions(...)
public class MyTest {

}

有一个

class MyModule extends AbstractModule {
    @Override
    protected void configure() {
         bind(MyService.class).to(MyFirstService.class);     
    }
}

由我的MyInjectorSource使用,我定义了cucumber.properties,我定义了guice.injector-source=MyInjectorSource;还有一个包含方案的功能文件。现在一切都在工作。

不,我想使用其他MyService实现运行MyStep步骤(当然我不会重复MyStep的代码)我定义了一个具有新场景和新测试类的新功能文件

@RunWith(Cucumber.class)
@CucumberOptions(...)
public class MyOtherTest {

}

现在我试图创建另一个SunjectorSource,但我无法配置它。

共有1个答案

贺高杰
2023-03-14

我发现的解决方案是使用从原始Cucumber runner继承的自定义Junit4 runner,并更改其< code>createRuntime方法。

最新的cucumber guice 1.2.5使用了几个阶段来创建注入器,不幸的是,它使用了全局变量cucumber.runtime.Env.INSTANCE。此变量由cucumber填充。属性和<code>System.getProperties。

流量为:

  • cucumber跑步者扫描可用的后端(在我的设置中是cucumber.runtime.java.JavaBackend
  • 可用的JavaBackend构造函数加载之一ObjectFactory(在我的设置中cucumber.runtime.java.guice.impl.GuiceFactory)
  • GuiceFactory via Inject torSourceFactory检查Env.INSTANCE,它将创建自定义Inject torSource或默认注入器

理想情况下,cucumber应该将其在开始时创建的“RuntimeOptions”传递给后端和InjectorSource,但不幸的是,它没有这样做,而是使用了全局变量。创建这样补丁并不容易,所以我的解决方案简化了这种方法,通过读取新的注释直接在自定义运行器中创建InjectorSource。

public class GuiceCucumberRunner extends Cucumber {

    public GuiceCucumberRunner(Class<?> clazz) throws InitializationError, IOException {
        super(clazz);
    }

    @Override
    protected Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) throws InitializationError, IOException {
        Runtime result = new Runtime(resourceLoader, classLoader, Arrays.asList(createGuiceBackend()), runtimeOptions);
        return result;
    }

    private JavaBackend createGuiceBackend() {
        GuiceCucumberOptions guiceCucumberOptions = getGuiceCucumberOptions(); 
        InjectorSource injectorSource = createInjectorSource(guiceCucumberOptions.injectorSource());
        ObjectFactory objectFactory = new GuiceFactory(injectorSource.getInjector());
        JavaBackend result = new JavaBackend(objectFactory);
        return result;
    }

    private GuiceCucumberOptions getGuiceCucumberOptions() {
        GuiceCucumberOptions guiceCucumberOptions = getTestClass().getJavaClass().getAnnotation(GuiceCucumberOptions.class);
        if (guiceCucumberOptions == null) {
            String message = format("Suite class ''{0}'' is missing annotation GuiceCucumberOptions", getTestClass().getJavaClass());
            throw new CucumberException(message);
        }
        return guiceCucumberOptions;
    }

    private InjectorSource createInjectorSource(Class<? extends InjectorSource> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            String message = format("Instantiation of ''{0}'' failed. InjectorSource must have has a public zero args constructor.", clazz);
            throw new InjectorSourceInstantiationFailed(message, e);
        }
    }

    static class GuiceFactory implements ObjectFactory {

        private final Injector injector;

        GuiceFactory(Injector injector) {
            this.injector = injector;
        }

        @Override
        public boolean addClass(Class<?> clazz) {
            return true;
        }

        @Override
        public void start() {
            injector.getInstance(ScenarioScope.class).enterScope();
        }

        @Override
        public void stop() {
            injector.getInstance(ScenarioScope.class).exitScope();
        }

        @Override
        public <T> T getInstance(Class<T> clazz) {
            return injector.getInstance(clazz);
        }
    }
}

 @Retention(RetentionPolicy.RUNTIME)
 @Target({ ElementType.TYPE })
 public @interface GuiceCucumberOptions {

     Class<? extends InjectorSource> injectorSource();

 }

@RunWith(GuiceCucumberRunner.class)
@GuiceCucumberOptions(injectorSource = MyInjector.class)
@CucumberOptions(
        ...
)
public class Suite {

}

我需要复制GuiceFactory,因为它没有公开普通的构造函数(!idspnonenote)。)

 类似资料:
  • 我对使用Guice有疑问。我有一个名为< code>Main的类,它是使用Guice和一个方法注入的构造函数,每次调用该方法都会创建一个类< code>AppThread的o thread对象。< code>AppThread是< code>Main中的私有类。问题是,在线程的执行过程中,我想创建一个class 的对象。此对象是使用Guice注入的构造函数。我不知道注入< code>ClassX的

  • 我有一个Maven模块,我在其中定义了一些跨其他几个Maven模块共享的UTIL。在本模块中,我想创建一些单例: 然后我将我的界面绑定到: 假设我想使用另一个Maven模块(比如web服务)中的这个单例,我该如何实现呢?我找到的唯一方法是在util Maven模块中创建一个类,如: 或者,我可以在Guice教程中看到的静态main方法中创建注入器,并将实例保存在某个地方。 然后从我的Web服务中执

  • 我试图在步骤定义中使用DI。我有一个模块, 并希望将此实例注入步骤定义的构造函数中。 我想我需要使用cucumber-guice.properties文件来配置GuiceFactory,但是我不知道这是什么?目前我得到的错误是, 我还应该使用提供程序进行构造函数注入吗?

  • 我已经使用google-guice和辅助注射机制有一段时间了。因为我在scala,刚刚发现scala-guice,我也对使用它感兴趣。但是我对如何使用辅助注射感到困惑。没有使用辅助注射的例子。 因此,我的问题是:是否可以使用scala guice辅助注射,如果可以,请提供一个简单的例子? 此外,对于google-guice,我使用以下库:javax.inject.jar、guice-3.0.jar

  • 我更新了createInjector调用以包含我的JPAPersisteModule。。。 在我的持久化单元声明如下:

  • 我正在尝试结合Guice的这3个功能:注入,多重绑定,泛型。我创建了一个生产项目的原型,所以这里是: 首先,这是泛型的一个小层次结构(在生产案例中,有N个实体的层次结构): 接下来,类ToCreate1和ToCreate2我想创建的工厂。 基类: 它的继承者: 然后,工厂本身: 所以,现在我想注入一个map,包含< i>Factory 因此,我使用配置方法创建了Guice的抽象模块: 所以,我注入