Ruby on rails 如何使用Rspec测试rubyonrails中的链式方法
我正试图决定如何测试一种方法,该方法只计算关联记录上的平均值。我关心的是测试实现与返回的实际结果 假设我有以下型号Ruby on rails 如何使用Rspec测试rubyonrails中的链式方法,ruby-on-rails,testing,rspec,Ruby On Rails,Testing,Rspec,我正试图决定如何测试一种方法,该方法只计算关联记录上的平均值。我关心的是测试实现与返回的实际结果 假设我有以下型号 class User has_many :interviews def interview_grade interviews.average(:score).round unless interviews.empty? end end class Interview belongs_to :user end 在user\u spec.rb中,我有 de
class User
has_many :interviews
def interview_grade
interviews.average(:score).round unless interviews.empty?
end
end
class Interview
belongs_to :user
end
在user\u 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\u grade
应该实际计算分数的总和(例如)。因为我只是测试调用了一个特定的方法链,所以通过测试不会告诉我结果实际上是不正确的
我已经尝试了stubinguser.conferences
,以便为测试设置可用的分数,但是在Rails 3中这似乎很难做到,因为关联是惰性加载的。i、 e.我不能仅仅创建一个访谈对象数组,因为它不响应平均方法
非常感谢您的建议。这是存根和模仿的错误用法
在这种情况下,您应该只测试interview\u grade
是否有效,当average
返回nil时(这是唯一的案例interview.empty?
)
average
方法由rails本身进行测试<我猜是ruby测试的code>round
方法。所以你不需要测试这个方法。这是只测试您自己的代码的一般想法
如果你想测试面试分数是如何计算的,你应该创建测试数据(用夹具或工厂)。因为在某些情况下,您应该单独测试系统的一部分,而在这种情况下,分离是错误的:interviews.average和interviews.empty?它们在代码中是依赖的,但在规范中是独立的
def面试等级
面试。平均(:分数)。尝试(:轮)
结束
如果您以这种方式重写您的方法,那么您就不需要在3年后再回到这个问题上来了。我会采取完全不同的做法
下面代码的好处是,为了给InterviewGrader编写测试,我不再需要担心如何获得分数
我只是给它分数,然后测试它给了我正确的输出
此外,我永远不需要担心InterviewGrader的底层实现。但是,如果以后更改逻辑,测试将失败
需要单独测试用户
上的新评分
方法
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
我更喜欢在这里使用try,我没有想到这一点。然而,我尽量避免使用工厂,因为它们速度慢。我更喜欢模拟user.interfaces,但正如我在问题中提到的,由于延迟加载关联,我还没有在Rails3中找到一种很好的方法来实现这一点。