Groovy насмешливый Файловая фабрика со Споком - PullRequest
1 голос
/ 24 февраля 2011

Я решил использовать фабрику файлов, чтобы смоделировать конструкцию объекта 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» не является нулевым, «currentFile» не является нулевым.

Внезапно он переходит к 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 ]

3 голосов
/ 24 февраля 2011

Спок в настоящее время не поддерживает методы насмешки, такие как File.write(), которые динамически добавляются Groovy, но отсутствуют в классе.Вы можете решить эту проблему, используя вместо этого Groovy MockFor, как вы это сделали для другого макета.

InvocationTargetException является внутренним исключением Groovy.Он окутывает NullPointerException, который вы видите.Спок достаточно умен, чтобы развернуть для вас исключение.

2 голосов
/ 25 февраля 2011

Питер, ты был прав.Фиксированный тест здесь:

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, переопределяя их в вашем пользовательском классе «обертки».

...