Спок повторно использует родовое закрытие - PullRequest
0 голосов
/ 02 мая 2018

У меня есть этот код в Споке:

 then:
    1 * dao.getByValue(Something.ONE, _ as String) >> {Something smth, String value ->
      return createSomething(smth).withValue(value).build()
    }

Это не совсем так, но вы поняли. Я хочу вернуть объект на основе аргументов, переданных методу, в реальной версии этот объект загружается из базы данных.

Дело в том, что у меня есть этот звонок во многих местах, и он везде выглядит одинаково. Могу ли я как-нибудь извлечь это замыкание и использовать его везде, например так:

then:
    1 * dao.getByValue(Something.ONE, _ as String) >> Closures.makeSomething

Я пытался использовать функцию извлечения Intellij, но там с типами это сходило с ума, после того, как я редактировал типы вручную, у меня были странные ошибки:

public static final Closure<Optional<Something>> makeSomething = { Something smth, String value ->
  return createSomething(smth).withValue(value).build()
}
...
1 * dao.getByValue(Something.ONE, _ as String) >> makeSomething
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'mypackage.MySpec$__clinit__closure1@1757cd72' with class 'mypackage.MySpec$__clinit__closure1' to class 'java.util.Optional'

Даже тот не работал, и я думал, что это будет:

public static final Closure<Optional<Something>> makeSomething = { Something smth, String value ->
  return createSomething(smth).withValue(value).build()
}
...
1 * dao.getByValue(Something.ONE, _ as String) >> {args -> makeSomething.call(args[0], args[1]) }
groovy.lang.MissingMethodException: No signature of method: mypackage.MySpec$__clinit__closure2.call() is applicable for argument types: (java.util.Arrays$ArrayList) values: [[mypackage.Something$$Lambda$6/1105423942@6f45df59, ...]]

Я не очень хорош в Groovy или Spock в общем, сейчас я просто пробую это.

Edit:

Рабочий код после предложения @tim_yates (все взаимодействие выполняется в вспомогательном методе):

then:
  interaction {
    somethingCall(2, Something.TWO)
    somethingCall(3, Something.ONE)
  }
}

private void somethingCall(int times, Something something) {
    times * dao.getByValue(something, _ as String) >> { Something smth, String value ->
        return createSomething(smth).withValue(value).build()
    }
}

Неработающий код, который я хотел бы (во возвращающем методе есть только возвращаемое значение):

then:
  2 * dao.getByValue(Something.TWO, _ as String) >> makeSomething
  3 * dao.getByValue(Something.ONE, _ as String) >> makeSomething
}

public static final Closure<Optional<Something>> makeSomething = { Something smth, String value ->
  return createSomething(smth).withValue(value).build()
}

Если я просто вставлю каждый >> makeSomething и напишу там его тело, то оно будет работать.

1 Ответ

0 голосов
/ 13 мая 2018

У вас есть концептуальная проблема здесь. Вы не можете просто отделить замыкание от предыдущего кода, потому что если вы посмотрите на него

dao.getByValue(something, _ as String) >> { Something smth, String value ->
  return createSomething(smth).withValue(value).build()
}

вы можете заметить, что smth и value внутри замыкания получают свои значения из getByValue(something, _ as String).

Теперь, если вы выделите встроенную часть замыкания в отдельный экземпляр замыкания, вы потеряете это соединение. Во-первых, у >> makeSomething нет параметров, во-вторых, вы не оцениваете замыкание makeSomething, т. Е. С правой стороны вы получаете не экземпляр Optional, а экземпляр Closure. Чтобы оценить замыкание, вы должны вызывать его с параметрами, то есть что-то вроде >> makeSomething(something, "dummy") будет работать. Но таким образом вы должны повторить первый getByValue параметр и создать пустышку для второго, неуказанного, потому что у вас нет простого способа сослаться на него, кроме как ввести еще одно замыкание, такое как >> { Something smth, String value -> makeSomething(smth, value) }. Но тогда вы не экономите много кода.

Это ваше решение, если это лучше, чем somethingCall(2, Something.TWO) (мне это действительно нравится) или если вы идете за моей придуманной конструкцией. Что я не могу для вас сделать, так это изменить синтаксис Groovy или Spock DSL только потому, что вы предпочитаете, чтобы он выглядел по-другому.

...