在Spock单元测试中,我试图测试独立于findRepositoriesByUsername
的方法getGithubUrlForPath
的行为,两者都属于同一服务。
重复尝试使用metaClass
失败了:
String.metaClass.blarg
生成错误No such property: blarg for class: java.lang.String
service.metaClass.getGithubUrlForPath
修改服务实例不起作用GithubService.metaClass.getGithubUrlForPath
修改服务类不起作用metaClass
上添加/修改方法,以及何时块都没有按预期工作测试:
package grails.woot
import grails.test.mixin.TestFor
@TestFor(GithubService)
class GithubServiceSpec extends spock.lang.Specification {
def 'metaClass test'() {
when:
String.metaClass.blarg = { ->
'brainf***'
}
then:
'some string'.blarg == 'brainf***'
}
def 'can find repositories for the given username'() {
given:
def username = 'username'
def requestPathParts
when: 'the service is called to retrieve JSON'
service.metaClass.getGithubUrlForPath = { pathParts ->
requestPathParts = pathParts
}
service.findRepositoriesByUsername(username)
then: 'the correct path parts are used'
requestPathParts == ['users', username, 'repos']
}
}
服务:
package grails.woot
import grails.converters.JSON
class GithubService {
def apiHost = 'https://api.github.com/'
def findRepositoriesByUsername(username) {
try{
JSON.parse(getGithubUrlForPath('users', username, 'repos').text)
} catch (FileNotFoundException ex) {
// user not found
}
}
def getGithubUrlForPath(String ... pathParts) {
"${apiHost}${pathParts.join('/')}".toURL()
}
}
我已经测试了groovy shell中的String.metaClass.blarg
示例(由grails启动),并且按预期进行了测试。
我在这里有一个根本的误解吗?我究竟做错了什么?有没有更好的方法来处理所需的测试(替换被测服务的方法)?
答案 0 :(得分:3)
这就是如何编写测试以使它们通过:
def 'metaClass test'() {
given:
String.metaClass.blarg = { -> 'brainf***' }
expect:
// note blarg is a method on String metaClass
// not a field, invoke the method
'some string'.blarg() == 'brainf***'
}
def 'can find repositories for the given username'() {
given:
def username = 'username'
def requestPathParts
when: 'the service is called to retrieve JSON'
service.metaClass.getGithubUrlForPath = { String... pathParts ->
requestPathParts = pathParts
[text: 'blah'] // mimicing URL class
}
service.findRepositoriesByUsername(username)
then: 'the correct path parts are used'
requestPathParts == ['users', username, 'repos']
}
答案 1 :(得分:0)
为什么不使用Spock强大的Mocking能力?
查看http://spockframework.github.io/spock/docs/1.0/interaction_based_testing.html#_creating_mock_objects
没有必要窥视元类本身,你可以创建一些存根对象,并且将调用所需的方法而不是原始方法。你也可以使用Groovy的MockFor和StubFor,它们可以更容易一些。
你不能完全信任spock测试规范中的元类。