2017-02-09 11 views
2

私は仕事中に最初のmodel specタスクを開始しました。多くのフィーチャー・スペックを書いた後で、(スペックを考慮しないで)モデル・スペックを書くという異なる視点に入るのは難しいです。私は私が経験していた難しさを説明するために、一例として、Orderモデルの方法を取るよ:Rails:このメソッドのモデル仕様を書くには?

def update_order_prices 
    self.shipping_price_cents = SHIPPING_PRICE_CENTS unless shipping_price_cents 

    return if order_lines.empty? 

    self.total_price_cents = calculate_order_price 
    self.total_line_items_price_cents = calculate_total_order_line_price 
    self.total_tax_cents = calculate_tax_amount 
end 

EDITのTLを、DR

を私は単に私を書き込み、その答えと完全に満足していますこのメソッドの仕様残りの投稿はこれまでに試したことを示していますが、この質問に答える必要はありません。

最初のアプローチ:まず

私がテストするために何を知りませんでした。私はメソッドが呼び出された時と場所を見つけようとしました。そして、このメソッドで触れられている属性がどのようなものであるべきかを知るシナリオを見つけることを試みました。要するに、私は文脈を理解しようと多くの時間を費やした。その後、同僚は、モデル仕様のメソッドをコンテキストに関係なく独立してテストする必要があると述べました。私はすべてのケースを特定していることを確認するだけです。だから、だろう、この方法は:(まだ行っていない場合)

  • それはorder_linesが
  • 空の場合、ORDER_LINEが
を設定している場合、それは値を設定し、早期返し
  • デフォルトに出荷価格のセントを設定し、

    現在のアプローチ:

    私はこれらの点のテストを書いてみましたが、まだ疑問が生じ:

    テスト1

    it 'sets shipping price cents to default (if not done already)' do 
        order.shipping_price_cents = nil 
        order.update_order_prices 
    
        expect(order.shipping_price_cents).to eq(Order::SHIPPING_PRICE_CENTS) 
    end 
    

    私は右のこの1つを得たと確信していますが、私が間違っていることを証明して自由に感じます。私はshipping_price_centsをnilに設定してそれを設定するコードをトリガし、セントでテストされたメソッドをモデルで定義されているデフォルト値と同じように呼び出します。

    テスト2

    it 'returns early if order_lines is empty' do 
        expect(order.update_order_prices).to eq(nil) 
    end 
    

    だからここで私はorder_lines協会にはオブジェクトが存在しない場合にメソッドが早く返すことをテストします。私はそれを行うための手がかりを持っていなかったので、私はコンソールに入って、注文を受け取り、それに関連したorder_linesを削除し、返されるものを見てメソッドを呼び出しました。

    2.3.1 :011 > o.order_lines 
    => #<ActiveRecord::Associations::CollectionProxy []> 
    2.3.1 :012 > o.update_order_prices 
    => nil 
    

    は、その後、関連するORDER_LINEでのご注文のために同じことをやった:

    2.3.1 :017 > o.update_order_prices 
    => 1661 
    

    だから私は、返される 'nil' のためにテストしました。しかし、私は正しいことをテストしているようには感じません。

    試験3

    it 'sets (the correct?) values if order_line is set' do 
    
        order_line = create(:order_line, product: product) 
        order = create(:order, order_lines: [order_line]) 
        order.update_order_prices 
    
        expect(order.total_price_cents).to eq(order.calculate_order_price) 
        expect(order.total_line_items_price_cents).to eq(order.calculate_order_line_price) 
        expect(order.total_tax_cents).to eq(order.calculate_tax_amount) 
    end 
    

    Iは、単に属性が、私は外見てはいけないように、それらは、実際の値を使用せずに設定されるものと等しいことをテスト。もし私が絶対値をテストしたいのであれば、この関数の外で調べて、メソッドをテストしないでOrderオブジェクトのステータスなどを調べなければなりません。テストので

    Failures: 
    1) Order Methods: #update_order_prices sets (the correct?) values if order_line is set 
    Failure/Error: expect(order.total_price_cents).to eq(order.calculate_order_price) 
    
    NoMethodError: 
        private method `calculate_order_price' called for #<Order:0x007ff9ee643df0> 
        Did you mean? update_order_prices 
    

    、渡された最初の2つのテストを実行する

    、3つ目はしませんでした。この時点で私は少し失われて、経験豊かな開発者がこの一見単純なテストをどのように書いているか聞いてもらいたいです。私はあなたがupdate_order_prices後に期待している正確な値に対して仕様にあると思い

    おかげ

  • 答えて

    1

    のは、あなたが、私は以下の期待他の方法について

    expect(order.total_price_cents).to eq(1000)

    同じことを追加したい10ユーロの合計金額を持っているあなたのためにと注文ラインを設定しましょう。一般的に私は特定の値に対してテストしようとします。また、プライベートメソッドの結果に依存している場合、結果についてのみ気にします。

    +0

    私はアプリの状態をテストしていませんか? – Flip

    +0

    いいえ、前に定義した前提条件で呼び出されたメソッドの正しい結果を指定するだけです。これは、あなたのアプリでは、注文ラインに関連する可能性のある製品は100ユーロですが、(モデル/ユニット)仕様では1ユーロに設定し、結果が期待どおりであることを確認することを意味します。状態は統合仕様でテストされます。 – basiszwo

    関連する問題