Groovy 如何编写自定义Spock交互迷你DSL来测试我的邮件发送?

Groovy 如何编写自定义Spock交互迷你DSL来测试我的邮件发送?,groovy,spock,Groovy,Spock,我很难为我的spock测试编写简洁易读的自定义交互 以下是我目前掌握的情况: class FunctionTestMailSpec extends Specification { ... def "process functional test email"(){ ... stuff that processes the mail and ends up calling sendMailSvc.sendEmail() ... then: "mail

我很难为我的spock测试编写简洁易读的自定义交互

以下是我目前掌握的情况:

class FunctionTestMailSpec extends Specification {
  ...


  def "process functional test email"(){

    ...
    stuff that processes the mail and ends up calling sendMailSvc.sendEmail()
    ...

    then: "mail should be sent to the expected address"

    // (A)
    1 * sendMailSvc.sendEmail(testMsg.sesMessageId, _ as Message ) >> {
      msgId, Message msg ->
      assert msg.subject == testMsg.variables.subject
      assert msg.to.flatten() == [mime.parseMailbox(keywordRealAddress)]
    }

    // (B)
    1 * sendMailSvc.sendEmail(testMsg.sesMessageId, _ as Message ) >> {
      msgId, Message msg -> assertMessage(
        msg, testMsg.variables.subject, keywordRealAddress)
    }

    // (C)
    1 * sendMailSvc.sendEmail(testMsg.sesMessageId, _ as Message ) >> {
      String msgId, Message msg ->
      new MessageAssertion().
        withSubject(testMsg.variables.subject).
        withTo(keywordRealAddress).apply(msgId, msg)
    }

    // (D)
    // GroovyCastException: Cannot cast object 'org.codehaus.groovy.runtime.MethodClosure@1e4c4fda' with class 'org.codehaus.groovy.runtime.MethodClosure' to class 'com.amazonaws.services.simpleemail.model.SendRawEmailResult'
    1 * sendMailSvc.sendEmail(testMsg.sesMessageId, _ as Message ) >>
      new MessageAssertion().
        withSubject(testMsg.variables.subject).
        withTo(keywordRealAddress).&apply
  }

  void assertMessage(
    Message message,
    String subject,
    String[] to
  ){
    assert message.subject == subject
    assert message.to.flatten() == to.collect{mime.parseMailbox(it)}
  }
}

class MessageAssertion implements BiFunction<String, Message, SendRawEmailResult> {
  String sesMessageId
  String subject
  Mailbox[] to = []

  MimeUtil mime = new MimeUtil()

  def withSubject(String subject){
    this.subject = subject
    this
  }

  def withSesMessageId(String sesMessageId){
    this.sesMessageId = sesMessageId
    this
  }

  def withTo(String[] to){
    this.to = to.collect{mime.parseMailbox(it)}
    this
  }

  @Override
  SendRawEmailResult apply(String sesMessageId, Message message){
    if( this.sesMessageId ){
      assert sesMessageId == this.sesMessageId
    }
    if( this.subject ){
      assert message.subject == this.subject
    }
    if( this.to ){
      assert message.to.flatten().toArray() == this.to
    }
    return null
  }

}
我需要做什么来定义一个DSL,它允许我编写这样的交互,或者接近它?

只是一个假设

您可能可以创建这样的类:

class A{
    String name_ 
    A make(String name){
        this.name_=name
        return this
    }
    A rightShift(B b){
        b.greet(name_)
        return this
    }
}
//aka SendRawEmailResult
abstract class B{
    abstract def greet(String name)
}
//aka MessageAssertion
class C {
    def asserts=[:]
    Object invokeMethod(String name, Object args){
        if(name.startsWith('with')){
            asserts[name.substring(4)]=args
            return this
        }
        throw new Exception("$name method not supported for ${this.getClass()}")
    }
    Closure apply(){
        return {String x->
            println "assert for `$x`"
            if(asserts.Subject){
                println "assert Subject here"
            }
            asserts.each{k,v->
                println "$k : [${v.getClass()}] $v"
            }
        }
    }
    String toString(){
        return "*** ${this.getClass()}${asserts}"
    }
}

new A().make('world') >> 
    new C().withQwe('qwe123').withZte('zte456').withSubject('subj').apply()

这不管用。必须从闭包接口添加两个ctor()(与委托、“所有者”和“thisObject”有关)。但更重要的是,它失败了,出现了与(D)相同的错误,表示它无法强制转换接近SendRawEmailResult的结果(这就是被模拟的方法sendEmail()应该返回的结果)。
class A{
    String name_ 
    A make(String name){
        this.name_=name
        return this
    }
    A rightShift(B b){
        b.greet(name_)
        return this
    }
}
//aka SendRawEmailResult
abstract class B{
    abstract def greet(String name)
}
//aka MessageAssertion
class C {
    def asserts=[:]
    Object invokeMethod(String name, Object args){
        if(name.startsWith('with')){
            asserts[name.substring(4)]=args
            return this
        }
        throw new Exception("$name method not supported for ${this.getClass()}")
    }
    Closure apply(){
        return {String x->
            println "assert for `$x`"
            if(asserts.Subject){
                println "assert Subject here"
            }
            asserts.each{k,v->
                println "$k : [${v.getClass()}] $v"
            }
        }
    }
    String toString(){
        return "*** ${this.getClass()}${asserts}"
    }
}

new A().make('world') >> 
    new C().withQwe('qwe123').withZte('zte456').withSubject('subj').apply()