2011-07-01 4 views
3

관련 레코드의 평균값을 계산하는 방법을 테스트하는 방법을 결정하려고합니다. 구현을 테스트하고 반환 된 실제 결과가 걱정됩니다. Rspec을 사용하여 Ruby on Rails의 연결 메소드를 테스트하는 방법

class User 
    has_many :interviews 

    def interview_grade 
    interviews.average(:score).round unless interviews.empty? 
    end 
end 

class Interview 
    belongs_to :user 
end 

그리고 내가 가지고있는 user_spec.rb에서

...

describe "interview_grade" do 
    let(:user) {User.new} 
    context "when the user has interviews" do 
    before { user.stub_chain(:interviews, :empty?){false} } 
    it "should return an average of the appraisal ratings" do 
     user.interviews.should_receive(:average).with(:score).and_return(3.2) 
     user.work_history_grade.should == 3 
    end 
    end 

    context "when the user has no interviews" do 
    before {Interview.destroy_all} 
    it "should return nil" do 
     user.interview_grade.should be_nil 
    end 
    end 

end 

이 테스트를 통과 ... 나는 다음과 같은 모델을 말해봐 그러나 그것은 나에게 깨지기 쉬운 느낀다. interview_grade이 실제로 합계 (예 :)을 계산해야하는 경우 어떻게됩니까? 특정 메서드 체인이 호출되었다는 것을 테스트하는 중이므로이 통과 테스트는 결과가 실제로 올바르지 않다고 말하지 않습니다.

시험용으로 사용 가능한 점수를 설정하기 위해 스텁을 시도했으나 연관성이 느린 로딩 방식 때문에 레일스 3에서 처리하기가 까다로워 보입니다. 즉, 평균 method에 응답하지 않기 때문에 인터뷰 개체 배열을 만들 수 없습니다.

큰 호응을 얻었습니다.

답변

1

을 조롱에 필요가 없습니다. 나는 완전히 다르게 접근 할 것입니다.

아래 코드의 이점은 InterviewGrader에 대한 테스트를 작성하기 위해 더 이상 점수 획득 방법에 대해 걱정할 필요가 없다는 것입니다.

나는 그저 점수를주고 테스트를 통해 올바른 결과를 얻을 수 있습니다.

또한 InterviewGrader의 기본 구현에 대해 걱정할 필요가 없습니다. 그러나 나중에 논리가 변경되면 테스트가 실패합니다.

User의 새로운 scores 방법은 별도로 테스트해야합니다.

class InterviewGrader 

    def self.run scores 
    new(scores).run 
    end 

    attr_reader :scores 

    def initialize(scores) 
    @scores = scores 
    end 

    def run 
    scores.inject { |sum, score| 
     sum + score 
    }.to_f/number_of_scores 
    end 

    private 

    def number_of_scores 
    scores.length 
    end 

end 


class User 
    has_many :interviews 

    def scores 
    interviews.map(&:score) 
    end 

    def interview_grade 
    InterviewGrader.run(scores) 
    end 
end 

class Interview 
    belongs_to :user 
end 
0

이것은 스텁 및 조롱의 잘못된 사용법입니다.

이 경우 average이 nil을 반환하는 경우에만 interview_grade이 작동하는지 테스트해야합니다 (이 경우는 interviews.empty?이 사용됩니다).

average 방법은 레일 자체로 테스트됩니다. 루비 테스트에 의한 round 방법 (아마). 따라서이 방법을 테스트 할 필요가 없습니다. 이는 자신의 코드 만 테스트하는 일반적인 아이디어입니다.

그리고 테스트하고 싶다면 interview_grade가 어떻게 계산되는지, 테스트 데이터를 작성해야합니다 (조명기 또는 공장 포함). 시스템의 일부분을 테스트해야하기 때문에 (이 경우) 분리가 잘못되었습니다 : interviews.average and interviews.empty? 귀하의 코드에 의존하지만, 사양에 독립적입니다.

def interview_grade 
    interviews.average(:score).try(:round) 
end 

이 방법으로 당신의 방법을 다시 작성하는 경우

, 당신 스텁 3 년 후이 다시 오는

+0

여기서 시도해보십시오. 나는 그 생각을하지 않았습니다. 그러나 공장을 사용하는 것을 피하려고합니다. 왜냐하면 공장이 느리기 때문입니다. 나는 user.interviews를 모의하고 싶다.하지만 질문에서 언급했듯이, 레일스 3에서 연결을 지연 적으로로드하기 때문에 좋은 방법을 찾지 못했다. –