Spock重用通用闭包

时间:2018-05-02 12:56:05

标签: groovy closures spock

我在Spock中有这个代码:

 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,我现在只是尝试这个。

修改

在@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 :(得分:0)

这里有一个概念性问题。你不能只是从前面的代码拆分闭包,因为如果你看它

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

您可能会注意到封闭内的smthvaluegetByValue(something, _ as String)获取其值。

现在,如果将内联闭包部分分解为独立的闭包实例,则会丢失该连接。首先,>> makeSomething没有参数,其次你没有评估makeSomething闭包,即在右手边你没有得到Optional个实例而是Closure>> makeSomething(something, "dummy")实例。为了评估闭包,你必须用参数调用它,即getByValue之类的东西可以工作。但是这样你必须重复第一个>> { Something smth, String value -> makeSomething(smth, value) }参数并为第二个未指定的参数组成一个虚拟对象,因为除了引入另一个像somethingCall(2, Something.TWO)这样的闭包之外你​​没有简单的方法来引用它。但是你没有保存很多代码。

这是你的决定,如果这比#include "conio.h" #include <iostream> #include <thread> #include <mutex> #include <queue> #include <atomic> #include <condition_variable> using namespace std; enum state_t{ READ = 0, WRITE = 1 }; mutex mu; condition_variable cv; atomic<bool> running; queue<int> buffer; atomic<state_t> state; void generate_test_data() { const int times = 5; static int data = 0; for (int i = 0; i < times; i++) { data = (data++) % 100; buffer.push(data); } } void ProducerThread() { while (running) { unique_lock<mutex> lock(mu); cv.wait(lock, []() { return !running || state == WRITE; }); if (!running) return; generate_test_data(); //producing here lock.unlock(); //notify consumer to start consuming state = READ; cv.notify_one(); } } void ConsumerThread() { while (running) { unique_lock<mutex> lock(mu); cv.wait(lock, []() { return !running || state == READ; }); if (!running) return; while (!buffer.empty()) { auto data = buffer.front(); //consuming here buffer.pop(); cout << data << " \n"; } //notify producer to start producing if (buffer.empty()) { state = WRITE; cv.notify_one(); } } } int main(){ running = true; thread producer = thread([]() { ProducerThread(); }); thread consumer = thread([]() { ConsumerThread(); }); //simulating gui thread while (!getch()){ } running = false; producer.join(); consumer.join(); } (我真的喜欢它)或者你选择我的设计构造更好。我不能为你做的是改变Groovy或Spock DSL语法只是因为你更喜欢它看起来不同。