Groovy 是否可以动态生成Spock测试方法?
我有很多重复的测试,我想以某种方式将它们抽象出来。助手方法很有用,但在一定程度上是有用的。如果我能以某种方式在Groovy 是否可以动态生成Spock测试方法?,groovy,spock,Groovy,Spock,我有很多重复的测试,我想以某种方式将它们抽象出来。助手方法很有用,但在一定程度上是有用的。如果我能以某种方式在规范中以编程方式生成测试方法,我将能够删除大量复制粘贴代码 具体地说,我正在测试RPC层的方法。如果没有以某种方式调用,大多数方法都会失败。所以我有斯波克测试方法,比如: def observer = Mock(StreamObserver) def rpc = new UserServiceRpc() def "draftToOutbox: should fail when call
规范中以编程方式生成测试方法,我将能够删除大量复制粘贴代码
具体地说,我正在测试RPC层的方法。如果没有以某种方式调用,大多数方法都会失败。所以我有斯波克测试方法,比如:
def observer = Mock(StreamObserver)
def rpc = new UserServiceRpc()
def "draftToOutbox: should fail when called without parent"() {
def request = draftToOutboxRequest().toBuilder().clearParent().build()
when:
rpc.draftToOutbox(request, observer)
then:
1 * observer.onError(_)
1 * observer.onCompleted()
}
def "outboxToDraft: should fail when called without parent"() {
def request = outboxToDraftRequest().toBuilder().clearParent().build()
when:
rpc.outboxToDraft(request, observer)
then:
1 * observer.onError(_)
1 * observer.onCompleted()
}
不幸的是,我对Groovy的元编程(编译时AST转换)功能不太熟悉,也不确定这是如何实现的,这是否可能,这是否是一个好主意。一方面,我有一些复制粘贴,但另一方面,我的测试非常可读。不过,我倾向于两全其美:不使用复制粘贴的可读性。在这种情况下,您可以使用一些groovy工具,如:
@Unroll
def "#method: should fail when called without parent"() {
given:
def request = "$methodToGetRequest"().toBuilder().clearParent().build()
when:
rpc."$methodToTest"(request, observer)
then:
1 * observer.onError(_)
1 * observer.onCompleted()
where:
methodToTest | methodToGetRequest
'draftToOutbox' | 'draftToOutboxRequest'
'outboxToDraft' | 'outboxToDraftRequest'
}
编辑
使用方法指针的示例:
@Shared
String subjectToTest
def setupSpec() {
subjectToTest = "sTring To Test"
}
def "test using method pointers"() {
when:
def result = methodPointer()
then:
result == expectecResult
where:
expectecResult | methodPointer
'STRING TO TEST' | subjectToTest.&toUpperCase
'string to test' | subjectToTest.&toLowerCase
}
在这种情况下,您可以使用以下groovy工具:
@Unroll
def "#method: should fail when called without parent"() {
given:
def request = "$methodToGetRequest"().toBuilder().clearParent().build()
when:
rpc."$methodToTest"(request, observer)
then:
1 * observer.onError(_)
1 * observer.onCompleted()
where:
methodToTest | methodToGetRequest
'draftToOutbox' | 'draftToOutboxRequest'
'outboxToDraft' | 'outboxToDraftRequest'
}
编辑
使用方法指针的示例:
@Shared
String subjectToTest
def setupSpec() {
subjectToTest = "sTring To Test"
}
def "test using method pointers"() {
when:
def result = methodPointer()
then:
result == expectecResult
where:
expectecResult | methodPointer
'STRING TO TEST' | subjectToTest.&toUpperCase
'string to test' | subjectToTest.&toLowerCase
}
由于Spock严重依赖于AST转换,我认为如果不构建自己的AST转换,就不可能生成测试方法。是的,这基本上是我问题的关键。但我肯定不是第一个遇到这个问题的人。我可以尝试重新构建它,这样我只需要在一个地方测试它,但在这种情况下这并不容易,因为我使用的是GRPCJava,它不允许我在RPC方法之前配置过滤器。我真的很想对所有方法进行测试@那么你认为我必须写一个编译时AST转换?您认为结果可读吗?听起来您还可以生成源代码作为替代方法。这可能比深入研究斯波克的AST更容易。Groovy AST转换通常读起来像埃及象形文字。由于斯波克严重依赖AST转换,我认为如果不构建自己的AST转换来生成测试方法,那么生成测试方法是不可能的。是的,这基本上是我问题的关键。但我肯定不是第一个遇到这个问题的人。我可以尝试重新构建它,这样我只需要在一个地方测试它,但在这种情况下这并不容易,因为我使用的是GRPCJava,它不允许我在RPC方法之前配置过滤器。我真的很想对所有方法进行测试@那么你认为我必须写一个编译时AST转换?您认为结果可读吗?听起来您还可以生成源代码作为替代方法。这可能比深入研究斯波克的AST更容易。Groovy AST转换通常读起来像埃及象形文字。是的,那会很漂亮,除非我正在测试void
methods在您的情况下,给定的块将只是rpc。“$methodName”(请求,观察者)
在expect块中,您将检查模拟迭代。我认为我无法在数据表的expect块中进行交互测试。我需要根据我的问题测试与观察者的交互。哦,那么在“where”表之前的“expect”块中,我可以断言观察者的交互?我要试试这个!谢谢。我更新了答案,给你一个确切的例子。希望它有帮助。是的,那会很漂亮,除非我正在测试void
methods在您的情况下,给定的块将是rpc.“$methodName”(请求,观察者)
,在expect块中,您将检查模拟迭代。我不认为我可以在数据表的expect块中进行交互测试。我需要根据我的问题测试与观察者的交互。哦,那么在“where”表之前的“expect”块中,我可以断言观察者的交互?我要试试这个!谢谢。我更新了答案,给你一个确切的例子。希望能有帮助。