Groovy mocking File构造函数,验证对新创建的文件的写入

时间:2011-02-24 11:36:10

标签: java groovy mocking

我试图模拟循环中生成的新文件。简化示例:

class FileClass {

  def basePath
  def listObjects = []

  def createFilePerObject() {
    listObjects.each {currentObject ->
      File currentFile = new File("${basePath.toString()}/${currentObject.objectName}")

      currentFile.write currentObject.objectContent   //Verify this behaviour!!
    }
  }

}

class SimpleObject {
  String objectName
  String objectContent
}

而且,测试:

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 dummyFile = new MockFor(File)
    def mockFile = new MockFor(File, true)  //Intercept constructor call

    mockFile.demand.with {
      File() {dummyFile}
    }

    when:
    mockFile.use {
      fileClass.createFilePerObject()
    }

    then:
    1 * mockFile.write(_)
  }

}

因此,正如您所看到的,我正在尝试验证新文件实际上是否有内容写入。

并且,我收到以下错误:

MockFor with constructor interception enabled is only allowed for Groovy objects but found: java.io.File

因此,据我所知,File在Groovy GDK(Groovy JDK)中进行了扩展,并且它还有其他(并且非常有用)方法。但是Groovy试图模拟java.io.File。

并且,根据错误的逻辑,我决定实际上像这样删除File构造函数:

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(basePath: ".", listObjects: listObjects)

    def mockFile = new MockFor(File)

    File.metaClass.constructor << {String filePath -> mockFile } //Return the mocked file, so it can be verified

    when:
    mockFile.use {
      fileClass.createFilePerObject()
    }

    then:
    1 * mockFile.write(_)
  }

}

并且收到了构造函数已经存在的警告(我想我毕竟不能再这样做了):

groovy.lang.GroovyRuntimeException: Cannot add new constructor for arguments [[class java.lang.String]]. It already exists!

因此,其中一个想法是实际模拟将在循环中生成新File对象的File Factory。但是,工厂至少可以说是无用的 - 它只能用于测试文件创建的能力。

所以,PowerMock不起作用(无法加载PowerMockRunner),任何想法如何模拟这个,不使用额外的库,而不是最终无用的类?

感谢。

1 个答案:

答案 0 :(得分:1)

我可以建议其他非纯测试方法。

对于这个测试,创建一个临时目录,在测试主题中设置basePath并允许测试实际写出文件。您的断言显然已经读取了文件以验证结果,但它将是一个完整的测试而不试图模拟JDK类。然后,测试拆解可以清理临时目录。

如果你真的开始进行内存单元测试,我恐怕你可能不得不使用JMockIt,如果你可以了解它并且文档可以模拟任何东西,包括部分内容JDK。