问答。 Trailbalzer 测试 - 契约法的含义

Q&A. Trailbalzer Testing - Implications of contract method

以下问答基于 Trailblazer book pp. ~50-60 中给出的示例,并根据我的特定要求进行了改编。您可以简单地将 ARInvoicear_invoice 视为 Thingthing,以了解书中的一般情况。

我的 operation.rb 文件是:

class ARInvoice < GLTransaction   class Create <
  Trailblazer::Operation

    include( Model )
    model( ARInvoice, :create )

    contract() do
      property( :invoice_number )
      property( :currency_code )
      property( :forex_rate )
      property( :gl_account_id )

      validates( :invoice_number, :presence => true )
      validates( :currency_code, :presence => true )
    end

    def process( params )
      @model = ARInvoice.new  # have to use instance variable here
      validate( params[ :ar_invoice ], @model ) do |f|
        f.save
      end
    end
  end
end

我从开拓者书中改编了这个测试:

it("INSERTs a valid invoice") do
  test_time = Time.now
  puts(test_time)
  ar_invoice = ARInvoice::Create.(
    :ar_invoice => {
      :invoice_number => 101,
      :gl_account_id => 1,
      :effective_from => test_time.to_s
    }
  ).model

  ar_invoice.persisted?.must_equal(true)
  ar_invoice.invoice_number.must_equal(101)
  ar_invoice.transaction_type.must_equal('IN')
  ar_invoice.effective_from.must_equal(test_time)
  ar_invoice.superseded_after.must_equal(nil)
end

我得到了这个错误:

ar_invoice crud Create#test_0001_INSERTs a valid invoice: \
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: \
gl_transactions.effective_from may not be NULL: \
INSERT INTO "gl_transactions" . . .

但我也看到了这个:

# Running:
2016-02-08 11:24:35 -0500
E

因此,test_time 值已设置。为什么它没有进入 effective_from 属性?

我在下面给出的答案。

问题是我没领会Trailblazer (TBR)中contract do/end块的意义。我最初读这本书的方式是合同与形式有关。我在 RoR 方面的经验使我将 form 一词映射到 view 一词。我的错。但也可能绊倒其他人。

正确的合同块包含缺少的属性:effective_from

contract() do
  property( :invoice_number )
  property( :currency_code )
  property( :forex_rate )
  property( :gl_account_id )

  property( :effective_from )

  validates( :invoice_number, :presence => true )
  validates( :currency_code, :presence => true )
end

现在,如果我将单词 form 映射到 params[ :model ],它会帮助我。因为调用 process 方法时在 params[ :model ] 哈希中查找的属性仅限于 contract do/end 块中明确列出的那些属性; 这就是为什么使用 TBR 时不需要强参数的原因

请注意,原始测试仍然失败,因为未满足 currency_code 验证。但在编写此测试时这是故意的。