2012-10-05 27 views
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(或別的東西)應用到這裏,只需要做很少的修改?

回答

1

你的第一步是設計依賴注入 - 避免構造函數和靜態方法,而是採取你需要的實例。看起來這些類型是Provider<DeviceEntity>,DevicesAccessorDeviceTypesAccessor

Providera 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"); 
    } 
    } 
} 

在這一點上,它是非常容易通過傳遞在跟蹤它返回實例的提供者寫一個測試,沿與模擬DevicesAccessor和模擬DeviceTypesAccessor。 (我建議Mockito。)如果您編寫自己的提供程序界面並刪除@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(); 
    } 
} 

但是,如果你想使用吉斯移除樣板,只寫了吉斯Module 。您的模塊需要將DeviceTypesAccessor和DevicesAccessor綁定到FleetManagerDatabaseHelper將返回的實例; Guice會看到DeviceEntity有一個無參數構造函數,並且能夠自動注入DeviceEntityProvider<DeviceEntity>。 (評論,如果你想我擴大Module看起來像什麼。)

希望這有助於!

+0

看起來像很多樣板代碼 –

+0

@Adrian大多數代碼是你的方法;唯一的樣板是頂部的一系列字段,以及填充它們的構造函數。這是一些樣板,是的,但從長遠來看可以節省您的可測試性和可配置性。另外,儘管我更喜歡「構造函數注入」,但您甚至可以直接用'@ Inject'標註注入的字段來跳過該過程。 –