- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我正在寻求使我的 Rails 测试更快。我只有 520 个测试,但它们在 bash 中运行需要 62 秒,在 Rubymine 中运行需要 82 秒。
作为典型 Controller 测试的示例,我使用此代码以@user 身份登录并在 CommentsController 中为我的 RSpec Controller 测试创建基本的@comment:
before(:each) do
@user = Factory.create(:user)
sign_in @user
@comment = Factory.create(:comment)
end
您可能会意识到...这很慢。它构建了一个 @user
,但也为该用户构建了关联。 @comment
也是如此。
所以我认为调用 Factory.build(:user)
可以解决问题……但我遇到了奇怪的错误。例如,current_user
返回 nil
。
所以...我决定使用 Factory.build()
并在我的父 Controller 中清除所有之前的过滤器。然而,当我之后检查 RSPec 日志时,我的 rspec 日志仍然说大量插入正在访问数据库(我们正在谈论仅 3 次测试的数百行代码!)
before(:each) do
@user = Factory.build(:user)
#sign_in @user
controller.stub(:authenticate_user!) #before_filter
controller.stub(:add_secure_model_data) #before_filter
controller.stub(:current_user).and_return(@user)
@comment = Factory.build(:comment)
end
可悲的是,上面的 before(:each)
block 对测试性能的影响为零。正如我发现的那样,调用 Factory.build()
仍将在内部调用子关联上的 Factory.create()
。
这是一个 before(:each)
block ,它有效地删除了 RSpec 日志中产生的垃圾。它使我的测试性能提高了 35-40%
before(:each) do
@user = Factory.build(:user, :role => Factory.build(:role))
#sign_in @user
controller.stub(:authenticate_user!)
controller.stub(:add_secure_model_data)
controller.stub(:current_user).and_return(@user)
# both of these are still super slow. WTF?!
@site_update = Factory.build(:site_update, :id => 5, :author => Factory.build(:user, :role => Factory.build(:role)))
@comment = Factory.build(:comment,
:author => Factory.build(:user, :role => Factory.build(:role)),
:commentable => @site_update)
end
这使测试运行得更快,但它也很丑陋。我们不能认真地为每个测试都写这个……是吗?太疯狂了。我不会这样做。
我还想指出,这些 Factory.build()
行中的任何一行仍然需要大约 0.15 秒,即使它们没有访问数据库!
仅运行 3 次测试仍然会导致 factory_girl PER 测试占用大约 0.3 到 0.35 秒的时间!我认为这是完全不能接受的。如果删除 Factory.build()
行,测试将在 0.00001 秒内运行。
我认为陪审团的意见是:factory_girl 是一个非常慢的库。不使用它是唯一的解决方案吗?
这是我的factories.rb
:
Factory.define :role do |f|
f.name "Admin"
end
Factory.define :user do |f|
f.first_name "Banoo"
f.last_name "Smith"
f.sequence(:email) { |n| "Banoo.Smith#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
end
Factory.define :admin do |f|
f.first_name "Banoo"
f.last_name "Smith"
f.sequence(:email) { |n| "admin#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
end
Factory.define :course_provider do |f|
f.first_name "Josh"
f.last_name "Bolson"
f.sequence(:email) { |n| "josh.bolson#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
end
Factory.define :director do |f|
f.first_name "Director"
f.last_name "Dude"
f.sequence(:email) { |n| "director#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
end
Factory.define :instructor do |f|
f.first_name "Instructor"
f.last_name "Dude"
f.sequence(:email) { |n| "instructor#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
end
Factory.define :trainee do |f|
f.first_name "Trainee"
f.last_name "Dude"
f.sequence(:email) { |n| "trainee#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
end
Factory.define :private_message do |f|
f.subject "Subject"
f.content "content"
f.is_deleted_by_sender false
f.association :sender, :factory => :user
end
Factory.define :recipient do |f|
f.is_read false
f.is_deleted false
f.association :receiver, :factory => :user
f.association :private_message
end
Factory.define :course_template do |f|
f.name "name"
f.description "description"
f.association :course_provider
end
Factory.define :site_update do |f|
f.subject "Subject"
f.intro "intro"
f.content "content"
f.association :author, :factory => :user
end
Factory.define :comment do |f|
f.content "content"
f.association :author, :factory => :user
f.association :commentable, :factory => :site_update
end
Factory.define :country do |f|
f.name "Liberty"
end
Factory.define :province do |f|
f.name "Freedom"
f.association :country
end
Factory.define :payment_plan do |f|
f.name "name"
f.monthly_amount 79
f.audience "Enterprises"
f.active_courses "500-2000"
end
Factory.define :company do |f|
f.name "name"
f.phone_number "455-323-2132"
f.address "address"
f.postal_code "N7G-5F4"
f.association :province
f.association :payment_plan
end
Factory.define :company_user do |f|
f.first_name "Dan"
f.last_name "Grayson"
f.sequence(:email) { |n| "dan.grayson#{n}@gmail.com" }
f.password "secretpassword"
f.association :role
f.association :company
end
Factory.define :course do |f|
f.notes "notes"
f.difficulty 100
f.association :course_template
f.association :instructor, :factory => :company_user
end
Factory.define :study_group do |f|
f.name "name"
end
Factory.define :help_category do |f|
f.name "name"
end
Factory.define :help_document do |f|
f.question "question"
f.content "content"
f.association :category, :factory => :help_category
end
Factory.define :tag do |f|
f.name "name"
end
Factory.define :partial_mapping do |f|
f.from_suffix "ing"
f.to_suffix "ing"
end
Factory.define :newsletter do |f|
f.subject "subject"
f.content "content"
end
Factory.define :press_contact do |f|
f.full_name "Banoo Smith"
f.email 'Banoo.Smith@gmail.com'
f.phone_number "455-323-2132"
f.address "address"
f.postal_code "N9B-3W5"
f.association :province
end
Factory.define :press_release do |f|
f.headline "Headline"
f.origin "origin"
f.intro "intro"
f.body "body"
f.association :contact, :factory => :press_contact
end
Factory.define :theme do |f|
end
和有趣的基准。调用 Factory.create(:user)
平均需要 0.1 到 0.14 秒:
$ rails runner 'Benchmark.bm {|x| x.report { 100.times { Factory.create(:user) } } }'
user system total real
9.940000 0.080000 10.020000 ( 14.872736)
即使是 Factory.build(:user)
也需要很长时间...而这是在打开 :default_strategy => :build
的情况下!
$ rails runner 'Benchmark.bm {|x| x.report { 100.times { Factory.build(:user) } } }'
user system total real
9.350000 0.030000 9.380000 ( 11.798339)
很明显,这证明 factory_girl 有问题。解决方案是摆脱它或确保它正在使用 Factory.build
。这就是答案。
既然基本解决了我自己的问题,我想知道为什么Factory_girl这么受欢迎,为什么是“常识”?可以客观地得出结论,无论使用 Factory Girl 可以获得什么好处——它有很多好处——都不值得付出性能代价。我确信可以开发出性能更高的更好的 factory gem……但遗憾的是,factory_girl 不是。
我下面的解决方案使用了基本的对象实例化和 stub ,并且测试继续通过。我认为在每次测试的基础上使用基本的 Ruby、 stub 和手动填充对象值是“正确”的做法,如果你想避免固定装置并在运行测试时获得高性能的话。
最佳答案
好吧,我想我会回答我自己的问题。我认为这是正确的答案,也许其他人可以从中学习,因为我不得不花几个小时来学习它。
以下是我获得 2000%(或 20 倍)速度提升的方法:
before(:each) do
@user = User.new
controller.stub(:authenticate_user!)
controller.stub(:current_user).and_return(@user)
controller.stub(:add_secure_model_data)
@site_update = SiteUpdate.new
@comment = Comment.new
end
解决方案就是不使用任何类型的工厂来进行 Controller 测试(或许还有其他类型的测试)。我建议仅在实在太痛苦而无法使用 Factory 时才使用 Factory。
所有 3 个测试现在都在 0.07 秒内运行!在 1.4 秒之前运行所有 3 个测试。
Factory_girl 只是一个非常慢的库。我不知道它到底在做什么,但它的配置文件不正确。
是的,我知道它做的不仅仅是简单的 MyClass.new
语句...但即使对于像 Ruby 这样较慢的脚本语言,性能也比基本类实例化慢很多数量级.它需要进行一些大规模优化,以便 Factory.build(:my_class)
与 MyClass.new
我建议 Factory_girl 的实现者尝试获取它,这样它的开销不会比基本的 MyClass.new
调用慢很多(不包括数据库开销......那不可能避免)。它应该提供一种构建对象的好方法,您不必为了获得此好处而付出 20 倍的性能损失。这不是一个可以接受的权衡。
这一切都太糟糕了,因为当您在 Controller 规范中打开 render_views
时,Factory.build
在 Controller 中会很好。应该有很大的动机来纠正这个问题。
与此同时,只需使用基本的 Ruby/Rails 类。我想您会惊讶于它们实际上有多快....
关于ruby-on-rails - 如果我调用 Factory.build 以使我的 Controller 测试快速,我怎样才能让 Factory Girl 永远不会访问数据库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6128476/
Xcode 4 中的以下操作有什么作用? 为测试而构建 为运行而构建 为分析而构建 为存档而构建 我不确定何时使用这些(或是否使用其中任何一个)。 最佳答案 Running 用于运行您的应用(在 Ma
工具: Jenkins 版1.470 Maven 2 颠覆 环境 假设我的构建有许多项目 A-D。如图所示,依赖关系图存在。也就是说:B 依赖于 A 中的类,C 依赖于 B 中的类,D 依赖于 A 中
我正在创建一个软件项目,我想使用 autotools 为我生成 makefile 等脚本,我手动创建了 Makefile.am 和 configure.in 文件,我正在使用 autogen.sh 脚
什么yarn build命令做什么? 是 yarn build和 npm build相同?如果不是有什么区别? 最佳答案 yarn build和 npm build默认情况下不是现有的命令。我想你是说
如果我有一个包含许多相互依赖的项目的大型代码库,例如,projects/A、projects/B 和 projects/C ,其中 A 需要 B,B 需要 C,每个项目都有一个Cake 构建脚本,例如
我正在尝试使用 Wix/Detox 来测试我的 react-native 应用程序(iOS 版本)。我已成功遵循 https://github.com/wix/detox/blob/master/do
我们有许多编译 .NET 代码的 Nant 脚本。这些构建需要 5 到 10 分钟才能运行,我想找到一种方法来加速它们。 我们的 Nant 脚本看起来像
你好 当我在 windows 下使用 gnu 构建 ffmpeg-3.4.1 时,谁能帮我解决这个错误: /tmp/9747a756ee05ef34cc3fcf51eabde826/sysroot/u
构建解决方案/项目/程序意味着什么?我想确保我的定义是正确的(所以我在交谈时听起来不像个白痴)。在 IDE 中,您可以(如果我错了,请纠正我)编译源代码/编程代码为计算机可读的机器代码。您可以调试程序
为什么 Eclipse 在构建 Android 项目时会陷入无限循环,用于构建工作区...和(重新)构建工作区...和(重新)构建工作区... 这是一个已知的错误吗? 摆脱这个循环的正确方法是什么?
我的 Angular 项目是 @Angular4.3.3 ng build -prod 构建需要 77 秒 ng build --prod --build-optimizer=true 构建需要 19
所以我刚刚使用命令创建了一个 React Native 项目 react-native init "项目名称" 我进入应用程序级别的 build.gradle 以连接 firebase,但出现错误提示
我想弄清楚 TFS Online 2017 中的两个预定义变量之间是否存在差异:$(Build.Repository.LocalPath)和 $(Build.SourcesDirectory) .我有
编译项目时,当系统用户名匹配时,此脚本应将 Xcode 项目的构建版本递增 1。请记住,这些只是 Target->Build Phases->Run Script in Xcode 中脚本(不是 Ap
是否有一种工具可以在给定 MS Build 项目文件的情况下构建一个视觉对象,显示将在何时以及从哪个导入文件执行哪个目标? 如果给定一个解决方案文件,它会构建项目构建顺序的视觉效果? 最佳答案 是的,
我正在尝试使用 Bazel 进行以下设置。通过调用“bazel build”,Python 脚本应该生成未知数量的具有随机名称的 *.cc 文件,然后将这些文件编译成单个静态库(.a 文件),所有这些
我正在将我的 Cmake 项目迁移到 Bazel。我项目的根目录是 build我用来运行 Cmake 的文件夹。 迁移到 Bazel ,我需要创建一个 BUILD我的项目根目录下的文件。但是,在 ma
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 5 年前。 此帖子已于
当我的Dockerfile如下所示时,它运行良好。 ... RUN pip install git+https://user_name:my_password@github.com/repo_name
当前的自动构建功能集是否可以从存储库中添加新标签并标记生成的图像?还是我需要3party服务将新标签自动推送到Docker Registry? 最佳答案 目前不行。 当前(2014年10月)尚无Doc
我是一名优秀的程序员,十分优秀!