我决定使用File Factory来模拟File对象构造。
class FileClass {
def basePath
def listObjects = []
def createFilePerObject() {
listObjects.each {currentObject ->
// Use some other libraries for mocking(cant run PowerMockito, Gareth Davis adviced me to use JMockit)
// File currentFile = new File("${basePath.toString()}/${currentObject.objectName}")
//File factory(The simplest of the solutions)...
File currentFile = FileFactory.makeFile("${basePath.toString()}/${currentObject.objectName}")
currentFile.write currentObject.objectContent //Verify this behaviour!!
}
}
}
class SimpleObject {
String objectName
String objectContent
}
//Really simple
class FileFactory {
def static makeFile(String pathFileName) {
return new File(pathFileName);
}
}
测试:
class FileClassTest extends Specification {
FileClass fileClass
def "test simple object"() {
def listObjects = []
SimpleObject object1 = new SimpleObject(objectName: "First object", objectContent: "First object content")
SimpleObject object2 = new SimpleObject(objectName: "Second object", objectContent: "Second object content")
SimpleObject object3 = new SimpleObject(objectName: "Third object", objectContent: "Third object content")
SimpleObject object4 = new SimpleObject(objectName: "Fourth object", objectContent: "Fourth object content")
listObjects << object1
listObjects << object2
listObjects << object3
listObjects << object4
fileClass = new FileClass(listObjects: listObjects, basePath: ".")
def mockFile = Mock(File)
def mockFileFactory = new MockFor(FileFactory)
mockFileFactory.demand.makeFile {mockFile} //Return the mocked file...
when:
mockFileFactory.use {
fileClass.createFilePerObject()
}
then:
1 * mockFile.write(_)
}
}
问题是NullPointerException失败了!?
使用调试器我得到:
currentFile.write currentObject.objectContent //Verify this behaviour!!
并且,经过验证,“当前文件”确实是测试中指定的模拟文件。 “currentObject.objectContent”不为null,“currentFile”不为null。
突然之间,它跳转到BaseSpecRunner.java到这个方法:
protected Object invokeRaw(Object target, MethodInfo method, Object[] arguments) {
if (method.isStub()) return null;
try {
return method.getReflection().invoke(target, arguments);
} catch (InvocationTargetException e) {
//Here it fails!
runStatus = supervisor.error(new ErrorInfo(method, e.getTargetException()));
return null;
} catch (Throwable t) {
Error internalError =
new InternalSpockError("Failed to invoke method '%s'", t).withArgs(method.getReflection().getName());
runStatus = supervisor.error(new ErrorInfo(method, internalError));
return null;
}
}
“InvocationTargetException是一个经过检查的异常,它包装了被调用的方法或构造函数抛出的异常。”大。
有什么想法吗?
感谢。
答案 0 :(得分:3)
Spock目前不支持像File.write()
这样的模拟方法,这些方法由Groovy动态添加但在类中不存在。您可以使用Groovy的MockFor
来解决此问题,就像您对其他模拟一样。
InvocationTargetException
是一个内部Groovy异常。它包裹了你所看到的NullPointerException
。 Spock非常聪明,可以解开你的异常。
答案 1 :(得分:2)
class FileClassTest extends Specification {
FileClass fileClass
def "test simple object"() {
def listObjects = []
SimpleObject object1 = new SimpleObject(objectName: "First object", objectContent: "First object content")
SimpleObject object2 = new SimpleObject(objectName: "Second object", objectContent: "Second object content")
SimpleObject object3 = new SimpleObject(objectName: "Third object", objectContent: "Third object content")
SimpleObject object4 = new SimpleObject(objectName: "Fourth object", objectContent: "Fourth object content")
listObjects << object1
listObjects << object2
listObjects << object3
listObjects << object4
fileClass = new FileClass(listObjects: listObjects, basePath: ".")
def mockFile = new MockFor(File)
//This is how i can verify that the write method was called 4 times(no more, no less)
// but im not using Spock and some of the advanced verification abilites that come with it...
mockFile.demand.write(4) {}
def mockFileFactory = new MockFor(FileFactory)
mockFileFactory.demand.makeFile(4) {new File(".")} //Fixed.
when:
mockFile.use {
mockFileFactory.use {
fileClass.createFilePerObject()
}
}
then:
// 1 * mockFile.write(_)
//Just pass... Verification is done by MockFor, not Spock
true
}
}
然而,我发现这与我以前的测试方法更加“协调”:
class FileClassTest extends Specification {
class FileCustomWrapper extends File {
def FileCustomWrapper(String pathname) {
super(pathname);
}
//Ovveride the DefaultGroovyMethods method, Spock can recognize it, its staticly written
// , and ovveriden only for the use of mocking...
def write(String s) {
metaClass.write(s)
//super.write(s)
}
}
FileClass fileClass
def "test simple object"() {
def listObjects = []
SimpleObject object1 = new SimpleObject(objectName: "First object", objectContent: "First object content")
SimpleObject object2 = new SimpleObject(objectName: "Second object", objectContent: "Second object content")
SimpleObject object3 = new SimpleObject(objectName: "Third object", objectContent: "Third object content")
SimpleObject object4 = new SimpleObject(objectName: "Fourth object", objectContent: "Fourth object content")
listObjects << object1
listObjects << object2
listObjects << object3
listObjects << object4
fileClass = new FileClass(listObjects: listObjects, basePath: ".")
def mockFile = Mock(FileCustomWrapper)
def mockFileFactory = new MockFor(FileFactory)
mockFileFactory.demand.makeFile(4) {mockFile} //Pass the Spock mock
when:
mockFileFactory.use {
fileClass.createFilePerObject()
}
then:
//You can use the verification...
4 * mockFile.write(_)
}
}
因此,您可以使用Spock通过在您的自定义“包装器”类中覆盖它们来模拟Groovy动态添加的方法。