如何在不重新测试胖模型的情况下测试瘦小的控制器?

时间:2013-04-24 09:04:58

标签: ruby-on-rails unit-testing model-view-controller tdd

在开始之前,我正在使用带有rspec,shoulda-matchers和factorygirl的rails来简化测试,所以如果这些库包含有助于解决下面问题的东西,请告诉我。

我正在设计我的控制器和模型,并且不确定如何测试这种情况。

我有一个游戏模型,可以包含一堆玩家。如果游戏还没有开始,玩家只能被移除,所以我在我的游戏模型中添加了remove_player方法并对其进行了彻底的测试。

在我的播放器控制器中,我有删除操作调用remove_player方法来实际完成工作,然后该操作会导致重定向。

如何在不重新测试方法的情况下测试控制器实际上正在执行的操作(调用remove_player)?我可以测试进行重定向,但如果将来删除对remove_player的调用,则不会失败。

我知道,shoulda-matchers有“should_validate_presence_of”和类似的东西,这个测试背后的想法是一样的,但不能用我自己的方法。

1 个答案:

答案 0 :(得分:1)

我昨晚尝试了嘲笑和存根,他们完全按照我的意愿行事。 RSpec's mocks非常容易上手,并且包含在rspec gem中。

存根的基本思想是替换您用于测试另一个对象的真实对象。在我的问题的例子中,我可以在测试我的播放器控制器时制作游戏模型的存根,并说gamestub.remove_player总是返回true。在RSpec你可以这样做

@game = double("game") #a double is rspec's mock/stub object
@game.stub(:remove_player?).and_return(true)

模拟就像有点不同,它不仅仅是你嘲笑对象的替代品,而且也是你测试条件的一部分。你不仅可以说你的假对象如果被调用会返回什么,但是它应该被调用n次(或者测试将失败),以及你希望它被调用的参数。在上面的例子中,我可以模拟一个游戏并说gamemock.remove_player应该被调用一次并在当前播放器中传递并返回true(如果我想测试测试失败时发生了什么,则为false)。这是一个例子,就像我为玩家控制器做的那样。

@game = double("game")
Game.should_receive(:find_by_id).with("123").and_return { @game }
@game.should_receive(:remove_player?).with(current_user).and_return(true)
delete :destroy, {:id => 123}
response.should do_whatever

模拟和存根非常相似。 This article试图突出差异。对我来说,它似乎基本上是你如何使用它们,因为模拟具有存根的所有功能,可以作为一个使用。这可能就是为什么RSpec将它们视为一种类型(双重)