您将如何使用rspec进行测试?
class SomeClass
def map_url(size)
GoogleMap.new(point: model.location.point, size: size).map_url
end
end
答案 0 :(得分:3)
你的测试似乎“非常耦合且易于模拟”的事实表明代码本身一次做了太多事情。
要突出显示这个问题,请查看map_url
的这个实现,这是无意义的(对于任何大小的输入都返回“foo”),然后通过测试:
class SomeClass
def map_url(size)
GoogleMap.new.map_url
GoogleMap.new(point: model.location.point, size: size)
return "foo"
end
end
请注意:
map_url
,而不是使用正确的参数发起的地图。map_url
的结果未被退回。我认为问题在于您构建代码的方式使其看起来比实际更简单。因此,您的测试过于简单,因此无法完全覆盖方法的行为。
此comment from David Chelimsky似乎与此相关:
TDD中有一条旧指南建议你应该听 你的测试,因为当他们受伤时通常会出现设计问题。 测试是被测代码的客户端,如果测试受到伤害,那么 完成代码库中的所有其他客户端。像这样的快捷方式很快 成为糟糕设计的借口。我希望它因为它而保持痛苦 应该伤害来做到这一点。
遵循这个建议,我建议首先将代码分成两个单独的方法,以隔离问题:
class SomeClass
def new_map(size)
GoogleMap.new(point: model.location.point, size: size)
end
def map_url(size)
new_map(size).map_url
end
end
然后你可以单独测试它们:
describe SomeClass do
let(:some_class) { SomeClass.new }
let(:mock_map) { double('map') }
describe "#new_map" do
it "returns a GoogleMap with the correct point and size" do
map = some_class.new_map('300x600')
map.point.should == [1,2]
map.size.should == '300x600'
end
end
describe "#map_url" do
before do
some_class.should_receive(:new_map).with('300x600').and_return(mock_map)
end
it "initiates a new map of the right size and call map_url on it" do
mock_map.should_receive(:map_url)
some_class.map_url('300x600')
end
it "returns the url" do
mock_map.stub(map_url: "http://www.example.com")
some_class.map_url('300x600').should == "http://www.example.com"
end
end
end
生成的测试代码更长,有3个规格而不是2个,但我认为它更清晰,更清晰地分离了代码中涉及的步骤,并完全涵盖了方法行为。如果这是有道理的,请告诉我。
答案 1 :(得分:0)
所以这就是我做到的,感觉非常紧密和脆弱,就像这样嘲笑它。建议?
describe SomeClass do
let(:some_class) { SomeClass.new }
describe "#map_url" do
it "should instantiate a GoogleMap with the correct args" do
GoogleMap.should_receive(:new).with(point: [1,2], size: '300x600') { stub(map_url: nil) }
some_class.map_url('300x600')
end
it "should call map_url on GoogleMap instance" do
GoogleMap.any_instance.should_receive(:map_url)
some_class.map_url('300x600')
end
end
end