RSpec测试方法的返回和继承

时间:2019-06-06 00:53:02

标签: ruby-on-rails rspec rspec-rails

我试图针对两个不同的问题编写两个RSpec测试,这些测试比我以前编写的要先进得多。

我要在控制器中测试的内容:

def index
  @buildings ||= building_class.active.where(place: current_place)
end

我尝试编写RSpec测试:

describe 'GET :index' do
    it "assigns @buildings" do
      @buildings ||= building_class.active.where(place: current_place)
    get :index
    expect(assigns(:buildings)).to eq([building])
  end
end

该测试失败,甚至无法运行,所以我知道我缺少某些东西。


第二个测试需要测试类方法的返回值。这是我需要在控制器中测试的内容:

def class_name
  ABC::Accountant::Business
end

这是我测试此方法的尝试:

describe "class name returns ABC::Accountant::Business" do
  subject do
    expect(subject.class_name).to eq(ABC::Accountant::Business)
  end
end

1 个答案:

答案 0 :(得分:0)

对于第一次测试,我会做这样的事情:

首先,我将.active.where(place: current_place)移至范围(我猜building_class返回Building或类似的内容)

class Building << ApplicationRecord
  scope :active_in, -> (place) { active.where(place: place)

那么对测试进行存根比较容易

describe 'GET :index' do
  it "assigns @buildings" do
    scoped_buildings = double(:buildings)

    expect(Building).to receive(:active_in).and_return(scoped_buildings)

    get :index
    expect(assigns(:buildings)).to eq(scoped_buildings)
  end
end

然后您的控制器将执行

@buildings ||= building_class.active_in(current_place)

这样,您就可以测试两件事:控制器实际上调用了作用域,并且控制器在@buildings变量上分配了返回的值(您实际上不需要测试实际的对象,您可以测试型号规格上的范围)。

就个人而言,我认为最好使用相同的范围概念来进行@buildings = current_place.active_buildings之类的测试,以测试您正在获取当前位置的活跃建筑物。


编辑:如果您不能修改控制器,则存根稍有不同,它暗示了一些我不希望显式测试的方法。

scoped_buildings = double(:buildings)

controller.stub_chain(:building_class, :active, :where).and_return(scoped_building)

get :index
expect(assings(:buildings)).to eq scoped_buildings

请注意,现在您的测试依赖于特定的实现,并且测试实现是一种不良习惯,应该测试行为而不是实现。


第二,我猜类似的东西应该起作用:

describe ".class_name" do
  it "returns ABC::Accountant::Business" do
    expect(controller.class_name).to eq(ABC::Accountant::Business)
  end
end

恕我直言,如果方法的名称令人困惑,class_name会提示它返回一个字符串,而不是返回一个名称,而是返回一个类。也许您可以将该方法更改为resource_class或不太混乱的东西。