2016-02-10 54 views
4

我使用CucumberGuice作为DI。 我遇到以下问题: 我有一个步骤即黄瓜与Guice - 多个guice注射器

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 { 

} 

现在我试图创建另一个InjectorSource但我无法对其进行配置。

+0

如果你所放置的“@Inject”标注在“@Before”挂钩?您可以根据标签创建不同的'@Before'钩子,例如'@ Before'('@ tag1')和'@Before'('@ tag2')。每个人都有不同的'@Inject'定义。 – MikeJRamsey56

+0

如何在评论中转义'@'? – MikeJRamsey56

回答

2

我找到的解决方案是使用自定义的Junit4 runner继承原始的黄瓜亚军并改变其方法createRuntime

最新的cucumber-guice 1.2.5使用几个阶段来创建注入器,不幸的是它使用全局变量cucumber.runtime.Env.INSTANCE。该变量从cucumber.propertiesSystem.getProperties填充。

流程是:

  • 黄瓜亚军扫描可用的后端(在我的设置是cucumber.runtime.java.JavaBackend
  • 一个可用ObjectFactory JavaBackend构造负荷(在我的设置是cucumber.runtime.java.guice。 impl.GuiceFactory)
  • 通过InjectorSourceFactory GuiceFactory检查Env.INSTANCE,它会创建自定义InjectorSource或默认注射器

理想情况下,黄瓜应该将其在开始时创建的'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(!)