0

考虑以下 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(或其他东西)并进行最少的更改?

4

1 回答 1

1

您的第一步是设计依赖注入——避免构造函数和静态方法,而是采用您需要的实例。看起来这些类型是Provider<DeviceEntity>DevicesAccessorDeviceTypesAccessor

Provider一个非常简单的 Guice 接口,它通过单个无参数方法提供其类型参数中的任何类的实例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能够自动注入。(如果您希望我扩展它的外观,请发表评论。)DeviceEntityProvider<DeviceEntity>Module

希望这可以帮助!

于 2012-10-05T15:28:16.623 回答