考虑以下servlet代码:
public class AddDevice extends JsonServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(final JsonServletRequest request,
final JsonServletResponse response) throws ServletException,
IOException {
try {
final DeviceEntity device = new DeviceEntity();
device.type =
FleetManagerDatabaseHelper
.deviceTypesAccessor()
.queryForId(Integer.valueOf(
request.getParameter(DeviceTypeEntity._ID)));
device.sn = request.getParameter(DeviceEntity._SN);
device.status = Long.valueOf(0);
FleetManagerDatabaseHelper.devicesAccessor().create(device);
}
catch (final SQLException e) {
throw new ServletException("device already exists");
}
}
}
此代码取决于DeviceEntity和FleetManagerDatabaseHelper类。 现在,我想编写一个测试,检查创建的实体是否填充了正确的类型,sn和状态值。 为此,我可以创建一个FleetManagerDatabaseHelperMockup类。
如果您在最小的变化中如何应用Google Guice(或其他内容)?
答案 0 :(得分:1)
您的第一步是设计依赖注入 - 避免构造函数和静态方法,而是接受您需要的实例。看起来这些类型是Provider<DeviceEntity>
,DevicesAccessor
和DeviceTypesAccessor
。
Provider
是a very simple Guice interface,它通过单个无参数方法get()
提供其类型参数中任何类的实例。如果您已绑定Foo
,Guice会自动知道如何绑定Provider<Foo>
。如果您的实例很昂贵,或者在servlet的生命周期内需要多个实例,那么它非常有用。(正如您所做的那样)。
重构依赖注入后,您的类将如下所示:
public class AddDevice extends JsonServlet {
private static final long serialVersionUID = 1L;
private final Provider<DeviceEntity> deviceEntityProvider;
private final DevicesAccessor devicesAccessor;
private final DeviceTypesAccessor deviceTypesAccessor;
@Inject
public AddDevice(Provider<DeviceEntity> deviceEntityProvider,
DevicesAccessor devicesAccessor,
DeviceTypesAccessor deviceTypesAccessor>) {
this.deviceEntityProvider = deviceEntityProvider;
this.devicesAccessor = devicesAccessor;
this.deviceTypesAccessor = deviceTypesAccessor;
}
@Override
protected void doGet(final JsonServletRequest request,
final JsonServletResponse response) throws ServletException,
IOException {
try {
final DeviceEntity device = deviceEntityProvider.get();
device.type = deviceTypesAccessor.queryForId(
Integer.valueOf(request.getParameter(DeviceTypeEntity._ID)));
device.sn = request.getParameter(DeviceEntity._SN)
device.status = Long.valueOf(0);
devicesAccessor.create(device);
} catch (final SQLException e) {
throw new ServletException("device already exists");
}
}
}
此时,通过传入跟踪其返回的实例的Provider以及模拟的DevicesAccessor和模拟的DeviceTypesAccessor来编写测试非常容易。 (我推荐Mockito。)如果您编写自己的Provider界面并删除@Inject
,则甚至不需要使用Guice;在测试中,您可以继续使用该构造函数,但是您希望使用以下构造函数来满足Java EE:
public AddDevice() {
this(new NewDeviceEntityProvider(),
FleetManagerDatabaseHelper.deviceTypesAccessor(),
FleetManagerDatabaseHelper.devicesAccessor());
}
private class NewDeviceEntityProvider implements Provider<DeviceEntity> {
@Override public DeviceEntity get() {
return new DeviceEntity();
}
}
但如果您确实想使用Guice删除该样板,只需编写一个Guice Module
。您的模块需要将DeviceTypesAccessor和DevicesAccessor绑定到FleetManagerDatabaseHelper将返回的实例; Guice会看到DeviceEntity
有一个无参数构造函数,并且能够自动注入DeviceEntity
和Provider<DeviceEntity>
。 (如果您希望我扩展Module
的外观,请发表评论。)
希望这有帮助!