Guice 中的协助式注入

Guice 的常规用法是把构造函数标记(Annotate)为 @Inject,这样 Guice 就会自动注入(Inject)并创建这个类的实例。例子如下,一个 Worker 依赖于一个 Connection。当有一个全局 Connection 的时候,Guice 就可以自动创建出一个 Worker 的实例出来。

但现实情况往往不是这样,Worker 可能还需要一个名字(Name)成员,这个成员也需要在构造的时候就确定下来。于是,构造函数就需要接受一个额外的参数,并且这个参数是不受 Guice 控制的。代码大致是这样:

注意第 5 行的 @Assisted 标记,这也是一个 Guice 的特性。它告诉 Guice,这个参数你不知道,每次使用的时候需要我来告诉你。那这个“告诉”的方法,是通过一个工厂方法。这种方法称为协助式注入(Assisted Injection),类似如下的代码:

在使用的时候,需要事先安装(Install)WorkerFactoryModule,然后就可以注入 WorkerFactory 了,获得 WorkerFactory 的实例之后,通过调用 create 方法就可以轻松创建出不同名字的 Worker 来。

在 Guice Module 中获得已绑定的实例

Guice 是一个 Java 中的依赖注入(Dependency Injection)的类库,说白了就是实现一套 Java 中的全局变量。

上周碰到一个 Guice 的使用问题,根本原因是核心架构不正确地使用了 Guice,导致测试代码写起来比较麻烦。不过核心代码一时半会还重构不了,只好委屈一下测试这边了。先来看一下代码:

其中 LoginServerModule 负责创建一个测试用的 login server,可以动态地创建测试账号并模拟用户登录等,方便测试;另外它还会创建一个 LoginServerConfiguration 的绑定(Binding),用来通知其它代码 login server 的地址啊等一系列信息。ProductServerModule 创建了我们的核心产品的 server,这是主要的测试目标。然后问题就来了,测试账号创建完成之后,死活登录不进去。

经过漫长的调试,发现问题出在 product server 中并没有使用全局的 injector,而是自己创建了一个,大致代码如下:

于是 TestModule 中的各种 binding,在 product server 中都是看不见的,如果要让 server 看见,就一定要在 serverOverrideModules 中添加。于是代码就大致要写成这样:

这样才能通过 LoginServerOverrideModule,去告诉 product server 去哪里登录。但是问题又来了,LogingServerConfiguration 是在 LoginServerModule 中绑定的,而根据 Guice 的变态规定,在 Module 中无法得到已经绑定的实例。这要怎么办?

后来看了一下文档,发现可以绕过这个限制,因为 Guice 可以对某个实例手动注入(Inject),代码如下:

主要是看第 7 行,requestInjector,当 LoginServerConfiguration 已经绑定过之后,LoginServerOverrideModule 就能获得它的实例。这个奇葩用法真令人无语……

WebDriver测试中设定浏览器窗口的大小

WebDriver是一个网页测试的框架,它可以启动不同的浏览器来测试同一个网页,有助于开发人员检测网站在不同的浏览器中的表现。

除了不同类型和版本的浏览器之外,浏览器窗口的大小也是测试的关键因素之一,因为网页在大小不同的窗口中表现可能不一样。于是除了测试不同的浏览器之外,在运行测试之前,我们还要调整窗口的大小。

如果你的测试是用Java实现的,且比较复杂,推荐使用JUnit的Rule来实现这一操作,如下:

TestWatcher.starting()会在每个测试用例之前执行一遍。代码中把窗口大小统一设置成了1366*768,这里只是抛砖引玉一下,你也可以使用参数来控制,实现每个测试用例有不同的设置。另外这段代码中使用了Guice来注于一个WebDriver实例,对Guice不熟的同学请移步这里