2016-07-15 486 views
1

我剛開始研究Java應用程序的Spock測試框架。我沒有以前的Groovy經驗。我們如何使用Spock框架將模擬注入構造函數?以下是我的代碼和測試示例。如何將mock對象注入構造函數?

public class ResourceClass { 
    private final IDynamoDBMapper factory = new DefaultDynamoDBClientFactory(DynamoDBConfig.fromProperties()).mapperClient(); 

    private ServiceClass service; 

    @Inject 
    public ResourceClass(ServiceClass service) { 
     this.service = service; 
    } 
} 

我試着創建如下的測試類。

class ResourceClassTest extends Specification { 
ResourceClass eventsResource 
ServiceClass service 

def setup() { 
    service = Mock(ServiceClass) 
    eventsResource = new ResourceClass(service) 
} 

但我在eventsResource =新ResourceClass(服務)

java.lang.NullPointerException: Domain name must be specified. 

at java.util.Objects.requireNonNull(Objects.java:228) 

任何建議得到例外下面有請?

回答

1

問題不在於將模擬注入到ResourceClass的構造函數中,因爲您只是調用傳遞給模擬的構造函數。此異常情況的原因是因爲這個字段聲明+ initialiazation的:

private final IDynamoDBMapper factory = new DefaultDynamoDBClientFactory(DynamoDBConfig.fromProperties()).mapperClient(); 

工廠現場的初始化會發生在執行構造函數之前(將實際複製到構造函數編譯期間開始)。

您可以檢查工廠初始化失敗的原因(例如檢查DynamoDBConfig.fromProperties()的工作方式以及應該在哪裏指定Dynamo數據庫連接的域屬性)或者您可以修改源代碼以將工廠對象注入Resource類相同的方式,你的服務做的,通過構造,然後通過測試IDynamoDBMapper的模擬到服務的構造函數:

public class ResourceClass { 
    private final IDynamoDBMapper factory; 
    private ServiceClass service; 

    @Inject 
    public ResourceClass(ServiceClass service, IDynamoDBMapper factory) { 
     this.service = service; 
     this.factory = factory; 
    } 
} 

class ResourceClassTest extends Specification { 
    ResourceClass eventsResource 
    ServiceClass service 
    IDynamoDBMapper mapper 

    def setup() { 
     service = Mock(ServiceClass) 
     mapper = Mock(IDynamoDBMapper) 
     eventsResource = new ResourceClass(service, mapper) 
    } 
} 

隨着您在測試資源類獲得更多的控制第二種方案,但第一個解決方案應該更容易

+0

謝謝蓋爾蓋伊。我更改了源代碼以將DynamoDBMapper注入資源類。這僅在使用Spock或mockito時纔會發生? – vamsi

+0

運行Spock測試時會發生這種情況,但它不是spock問題,但是當您運行應用程序和運行測試時,類路徑通常會有所不同。因此,如果運行應用程序時在類路徑中具有dynamo數據庫配置文件,但在運行測試時不需要 –

1

Eit她需要以某種方式嘲笑你的DefaultDynamoDBClientFactory.mapperClient()或者讓它注射,否則它會尋找真正的實例,並會失敗。

public class ResourceClass { 
    private IDynamoDBMapper factory; 
    private ServiceClass service; 

    @Inject 
    public ResourceClass(IDynamoDBMapper factory, ServiceClass service) { 
     this.factory = factory; 
     this.service = service; 
    } 
} 

那麼你應該能夠單元測試你的resourceClass在下面一個奇特的方式,

class ResourceClassSpec extends Specification { 
    ResourceClass eventsResource 

    def setup() { 
     eventsResource = new ResourceClass(factory: Mock(IDynamoDBMapper), service: Mock(ServiceClass)) 
    } 

    def 'test does something'() { 
     given: 'given x' 
      // 
     when: 'when you call some method of resourceClass' 
      // 
     then: 'what you expect' 
      // 
      1 == 2 
    } 
}