2011-02-24 60 views
1

我决定使用File Factory来模拟File对象的构造。Groovy嘲笑Spock的文件工厂

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是经过检查的异常包装由调用方法或构造函数抛出的异常。”大。

任何想法?

谢谢。

回答

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(_) 
    } 
} 

所以,你可以使用斯波克嘲笑Groovy动态添加的方法通过在您的自定义“包装器”类中重写它们。

3

Spock目前不支持类似File.write()的模拟方法,它们是由Groovy动态添加的,但不在类中。您可以通过使用Groovy的MockFor来解决这个问题,就像您为其他模拟做的那样。

InvocationTargetException是内部Groovy异常。它包装你看到的NullPointerException。 Spock足够聪明,可以为你解开例外情况。