2016-07-15 480 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 
    } 
}