对于单元测试,我需要模拟在Grails服务中使用的几个与Apache Thrift相关的Java类(THttpClient,TBinaryProtocol和生成的客户端),但在使用通常的模拟技术时遇到了几个例外。我在服务中创建了getter(而不是在我测试的方法中使用新的运算符)。解决的一个问题是Thrift类没有默认构造函数,所以我创建了一个子类来满足模拟的要求:
class TestableTHttpClient extends THttpClient {
public TestableTHttpClient() {
super("http://example.com");
}
public TestableTHttpClient(String url) {
super(url);
}
}
我尝试使用mockFor()进行模拟,但得到 GroovyCastException :错误地将地图投射到MyServiceTests $ TestableTHttpClient,原因:null:
def mockTHttpClient = mockFor(TestableTHttpClient, true)
mockTHttpClient.demand.open { }
mockTHttpClient.demand.close { }
def mockTHttpClientInstance = mockTHttpClient.createMock() // fails
我尝试使用相同的GroovyCastException进行地图强制:将地图投射到MyServiceTests时出错错误$ TestableTHttpClient
def mockTHttpClientInstance = [
open: { },
close: { }
] as TestableTHttpClient]
我尝试过使用与上述相同的例外情况。
def helperMethod = { assert 1 == 1 }
def helper = [open:helperMethod, close:helperMethod]
def mockTHttpClientInstance = helper as TestableTHttpClient // fails
我对元类进行了更改,它传递了两个类,但最后一个类(Client)我需要返回一个特定的模拟值。相反,真正的方法被调用:TTransportException:没有更多的数据可用。
def mockTHttpClientInstance = new TestableTHttpClient()
mockTHttpClientInstance.metaClass.invokeMethod = { String name, args -> }
def mockTBinaryProtocolInstance = new TestableTBinaryProtocol()
mockTBinaryProtocolInstance.metaClass.invokeMethod = { String name, args -> }
def mockClientInstance = new TestableClient()
// mockClientInstance.metaClass.invokeMethod = { String name, args -> }
mockClientInstance.metaClass.methodINeedToMockResults = { String name -> true }
def mockMyService = [
getTHttpClient: { String -> mockTHttpClientInstance },
getTBinaryProtocol: { TTransport -> mockTBinaryProtocolInstance },
getClient: { TProtocol -> mockClientInstance }
] as MyService
有什么建议吗?我已经阅读了http://grails.org/doc/latest/guide/testing.html并且我知道的Grails书籍除了域名和控制器之外几乎没有其他测试。