Search code examples
cdiguicecucumber-jvmcucumber-junit

Guice - Binding classes from resource producer


My purpose is to produce EntityManager and Logger SFL4J implementations for my cucumber guice unit tests.

I've created the following resource producer

public class MockResourcesWeb {

    private static final Logger logger = LoggerFactory.getLogger(MockResourcesWeb.class);

    private EntityManager entityManager;

    @PostConstruct
    void init() {
        try {
            entityManager = Persistence.createEntityManagerFactory("h2-test").createEntityManager();
        } catch (Exception e) {
            logger.warn("Failed to initialize persistence unit", e);
        }
    }

    @Produces
    public EntityManager getEntityManager(InjectionPoint injectionPoint) {
        return entityManager;
    }

    @Produces
    public Logger produceLog(InjectionPoint injectionPoint) {
        return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
    }

}

Now I guess I should bind those classes using my implementation of AbstractModule so: public class ServiceModule extends AbstractModule { @Override protected void configure() { bind( EntityManager.class ).to(?); // ... (further bindings) } }

I have no idea how to realize this. I've also tried by expliciting it:

bind( EntityManager.class ).to(Persistence.createEntityManagerFactory("h2-test").createEntityManager());

But it still fails to compile.

Any suggestions ?


Solution

  • My purpose is to produce EntityManager and Logger SFL4J implementations for my cucumber guice unit tests.

    To have instance of EntityManager and SFL4J using guice injection

    you can use cucumber-guice as below

      <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-guice</artifactId>
                <version>6.4.0</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.google.inject</groupId>
                <artifactId>guice</artifactId>
                <version>4.2.3</version>
                <scope>test</scope>
            </dependency>
    

    Then in a Global class

    import com.google.inject.Singleton;
    import io.cucumber.guice.ScenarioScoped;
    
    // Scenario scoped it is used to show Guice
    // what will be the shared classes/variables and instantiate them only in here
    @ScenarioScoped
    //@Singleton
    public class Global {
     
       public EntityManager  entityManager = new EntityManager();
    }
    

    Create a BasePage class and pass Global in constructor

    //import classes   
    public class BasePage {
    
        protected Global global;
    
        public BasePage(Global global) {
            this.global = global;
        }
    }
    

    Now in your stepdefinitions ( unit tests or other cucumber tests)

      import com.google.inject.Inject;
      //import other classes as necessary
    
    public class StepDefs extends BasePage {
        
             public static EntityManager entityMgr; 
        
            @Inject
            public StepDefs(Global global) {
                super(global);
                StepDefs.entityMgr = global.entityManager
            }
         //use entityMgr as needed
    
         //note that a new instance of entityMgr will be created for each scenario in feature file`
         // to create an instance that will last for all tests use @singleton in Global class . ex : for sfl4j
      }