How to make a class’s constructor unit testable when its instantiating a Guice module in it?

Tags: , , , ,



I have the below mentioned class in a library module, which the clients will use to interact with database. I have a public constructor that takes a parameter from the user of this library, but the problem with this is that, its a Guice module getting instantiated inside this constructor. So when I try to write a unit test for this DataPersistence clasas, I cannot inject the module. I don’t want the real Guice module to be instantiated because that will create database connections and all.

public class DataPersistence {
    
    private MyDAO myDao;

    public DataPersistence(MyConfig myConfig) {
        myDao = Guice.createInjector(new MyDataModule(myConfig)).getInstance(MyDAO.class);
    }
    
    public String createEntry(final CreateIndexInput createIndexInput) throws IOException {
        return myDao.createEntry(createIndexInput);
    }

    public int indexDocument(final String indexName, final String jsonDocument) throws IOException {
        return myDao.indexDocument(indexName, jsonDocument).status().getStatus();
    }

    public SearchResult searchDocument(final String indexName, final Map<String, Object> queryMap)
            throws IOException {
        return myDao.searchDocument(indexName, queryMap);
    }
}

How can I convert this class to a utility where I have a way to mock the Guice module without triggering the real module? I tried making the constructor private, and added a “create” method and made the class final. But this way, all the methods would become static, allowing the user to call the methods, without having to call the “create” method first where I instantiate the myDao class.

Any help would be much appreciated.

Answer

Something like:

public interface Config{ ... }

public class MyConfig implements Config{ ... }

public interface InjectorFactory {
  public MyDAO generate();
}

public class MyInjectorFactory{
  private MyConfig myConfig;
  public InjectorFactory(MyConfig myConfig){
    this.myConfig = myConfig;
  }
  public MyDAO generate(){
    return Guice.createInjector(new MyDataModule(myConfig)).getInstance(MyDAO.class);
  }
}

public class DataPersistence { 
  private MyDAO myDao;
  public DataPersistence(InjectorFactory factory) {
    myDao = factory.generate();
  }
}

Then to test, you can build DataPersistence with a mocked InjectorFactory that returns a mocked MyDAO



Source: stackoverflow