gpt4 book ai didi

ruby-on-rails - 何时以及何时不 stub /模拟测试

转载 作者:数据小太阳 更新时间:2023-10-29 06:54:48 25 4
gpt4 key购买 nike

我正在齐心协力围绕 Rspec 进行研究,以便转向更多的 TDD/BDD 开发模式。但是,我还有很长的路要走,并且在一些基础知识上苦苦挣扎:

比如,我究竟什么时候应该使用模拟/ stub ,什么时候不应该?

以这种情况为例:我有一个 Site 模型 has_many :blogsBlog 模型 has_many :articles。在我的 Site 模型中,我有一个回调过滤器,它为每个新站点创建一组默认的博客和文章。我想测试该代码,所以这里是:

describe Site, "when created" do

include SiteSpecHelper

before(:each) do
@site = Site.create valid_site_attributes
end

it "should have 2 blogs" do
@site.should have(2).blogs
end

it "should have 1 main blog article" do
@site.blogs.find_by_slug("main").should have(1).articles
end

it "should have 2 secondary blog articles" do
@site.blogs.find_by_slug("secondary").should have(2).articles
end

end

现在,如果我运行那个测试,一切都会通过。然而,它也很慢,因为它要为每一个测试创建一个新站点、两个新博客和三个新文章!所以我想知道,这是否适合使用 stub ?让我们试一试:

describe Site, "when created" do

include SiteSpecHelper

before(:each) do
site = Site.new
@blog = Blog.new
@article = Article.new
Site.stub!(:create).and_return(site)
Blog.stub!(:create).and_return(@blog)
Article.stub!(:create).and_return(@article)
@site = Site.create valid_site_attributes
end

it "should have 2 blogs" do
@site.stub!(:blogs).and_return([@blog, @blog])
@site.should have(2).blogs
end

it "should have 1 main blog article" do
@blog.stub!(:articles).and_return([@article])
@site.stub_chain(:blogs, :find_by_slug).with("main").and_return(@blog)
@site.blogs.find_by_slug("main").should have(1).articles
end

it "should have 2 secondary blog articles" do
@blog.stub!(:articles).and_return([@article, @article])
@site.stub_chain(:blogs, :find_by_slug).with("secondary").and_return(@blog)
@site.blogs.find_by_slug("secondary").should have(2).articles
end

end

现在所有的测试都通过了,而且速度也快了一些。但是,我将测试的长度加倍了,整个练习让我觉得毫无意义,因为我不再测试我的代码,我只是在测试我的测试。

现在,要么我完全错过了模拟/ stub 的要点,要么我从根本上错误地处理了它,但我希望有人能够做到:

  • 改进我上面的测试,以便它以实际测试我的代码而不是我的测试的方式使用 stub 或模拟。
  • 或者,告诉我是否应该在这里使用 stub - 或者实际上这是否完全没有必要,我是否应该将这些模型写入测试数据库。

最佳答案

But, I've doubled the length of my tests and the whole exercise just strikes me as utterly pointless, because I'm no longer testing my code, I'm just testing my tests.

这里是关键。不测试您的代码的测试没有用。如果您可以消极地更改您的测试应该测试的代码,并且测试没有失败,那么它们就不值得拥有。

根据经验,除非万不得已,否则我不喜欢模拟/ stub 任何东西。例如,当我编写 Controller 测试时,我想确保在记录保存失败时发生适当的操作,我发现将对象的 save 方法 stub 以返回 false 更容易,而不是为了确保模型无法保存而精心设计参数。

另一个例子是一个名为 admin? 的助手,它根据当前登录的用户是否是管理员返回 true 或 false。我不想通过伪造用户登录,所以我这样做了:

# helper
def admin?
unless current_user.nil?
return current_user.is_admin?
else
return false
end
end

# spec
describe "#admin?" do
it "should return false if no user is logged in" do
stubs(:current_user).returns(nil)
admin?.should be_false
end

it "should return false if the current user is not an admin" do
stubs(:current_user).returns(mock(:is_admin? => false))
admin?.should be_false
end

it "should return true if the current user is an admin" do
stubs(:current_user).returns(mock(:is_admin? => true))
admin?.should be_true
end
end

作为中间立场,您可能需要查看 Shoulda .这样你就可以确保你的模型有一个定义的关联,并相信 Rails 已经过充分测试,关联将“正常工作”,而无需创建关联模型然后计算它.

我有一个名为 Member 的模型,基本上我的应用程序中的所有内容都与之相关。它定义了 10 个关联。我可以测试这些关联中的每一个,或者我可以这样做:

it { should have_many(:achievements).through(:completed_achievements) }
it { should have_many(:attendees).dependent(:destroy) }
it { should have_many(:completed_achievements).dependent(:destroy) }
it { should have_many(:loots).dependent(:nullify) }
it { should have_one(:last_loot) }
it { should have_many(:punishments).dependent(:destroy) }
it { should have_many(:raids).through(:attendees) }
it { should belong_to(:rank) }
it { should belong_to(:user) }
it { should have_many(:wishlists).dependent(:destroy) }

关于ruby-on-rails - 何时以及何时不 stub /模拟测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3705265/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com