如何使用Guice和Play框架正确地实现和测试映射绑定



我刚开始使用Guice and Play,所以我想这是一个很长但很基本的问题。我在这里查看了指南:http://eng.42go.com/play-framework-dependency-injection-guice/但我不知道我的代码为什么会失败。

首先,我有一个全局注射器:

public class GlobalInjector {
    private static Injector guiceInjector;
    private static List<AbstractModule> modules = new ArrayList<AbstractModule>();
    public static Injector getInjector() {
        return guiceInjector;
    }
    public static loadModules() {
        guiceInjector = Guice.createInjector(modules);
    }
    public static addModule(AbstractModule module) {
        modules.add(module);
    }
}

此外,我还通过扩展GlobalSettings类(也修改了application.global)将Guice添加到Play中

public class GuiceExtendedSettings extends GlobalSettings {
    @Override
    public void onStart(Application app) {
        GlobalInjector.loadModules();
    }
    @Override
    public <A> A getControllerInstance(Class<A> controllerClass) {
         return GlobalInjector.getInjector().getInstance(controllerClass);
    }
}

然后我让我的测试模块在Play中充当插件(一些所需的方法被省略了,因为它们在这篇文章中什么都不做):

public class TestModule extends AbstractModule implements Plugin {
    @Override
    public void configure() {
        // Worker is a simple class
        Worker worker = new SimpleWorker();
        MapBinder<String, Worker> mapBinder = MapBinder.newMapBinder(binder(), String.class, Worker.class);
        mapBinder.addBinding(worker.getName()).toInstance(worker);
    }
    @Override
    public void onStart() {
        GlobalInjector.addModule(this);
    }
}

Worker是一个简单的接口:

public interface Worker {
    public String getName();
    public String getResult();
}

SimpleWorker:

public class SimpleWorker implements Worker {
    public String getName() {
        return "SimpleWorker";
    }
    public String getResult() {
        return "works";
    }
}

这是一段显示控制器逻辑的代码:只需在映射注入的中打印所有工作结果

public class TestController extends Controller {
     @Inject
     Map<String, Worker> workers;
     public Result showWorkers() {
         StringBuilder sb = new StringBuilder();
         for (Worker worker : workers) {
             sb.append(worker.getName() + ": " + worker.getResult() + "</br>");
         }
         return ok(sb.toString()).as("text/html");
     } 
}

好的。为了实现这一点,我在play.plugins:中放入了以下行

100:test.TestModule

我的想法是:Play加载插件(TestModule)->TestModule将自己添加到GlobalInjector->GlobalInject器创建Guice注入器->Guice将映射注入控制器

但是结果是吉斯没有注入地图。地图仍然是null

我应该如何测试它(即,我如何将不同的工作人员注入该映射?我在上面的代码中对该部分进行了硬编码。但我正在寻找一种通过使用不同模块的动态方式。)

public class Test {
    @Test
    public void testInjector() {
        running(fakeApplication(), new Runnable() {
           public void run() { 
               // how can I inject using different modules here?
           }
        });
    }
} 

您需要使用fakeApplication助手方法,该方法允许您指定全局设置对象和其他插件。看见http://www.playframework.com/documentation/api/2.1.x/java/play/test/Helpers.html#fakeApplication(java.util.Map、%20java.util.List、%20play.GlobalSettings)了解详细信息。

但基本上,你的测试应该看起来像:

public class Test {
    @Test
    public void testInjector() {
       Map<String, Object> config = new HashMap<String, Object>();
       // add any additional config options, e.g. in-memory db
       List<String> plugins = new ArrayList<String>();
       plugins.add("full.package.name.TestModule");
       GlobalSettings global = null;
       try {
           global = (GlobalSettings) Class.forName("full.package.name.GuiceExtendedSettings").newInstance();
       } catch(Exception e) {}
       running(fakeApplication(config, plugins, global), new Runnable() {
           public void run() { 
               // do some assertions
           }
        });
    }
}

您还需要确保guide实例化了测试控制器,或者workers映射不会被注入。