28、调试、测试与性能分析:Rails 应用开发必备技能

调试、测试与性能分析:Rails 应用开发必备技能

在开发 Rails 应用时,测试和调试是确保应用质量和性能的关键环节。下面将深入探讨如何进行测试以及使用不同工具进行调试。

1. 测试套件的运行

在开发过程中,我们需要确保新增的测试用例和现有的测试用例都能通过。可以使用 rake 来运行整个测试套件,命令如下:

$ rails test

运行结果示例如下:

Running via Spring preloader in process 60620
Run options: --seed 20795
# Running:
....................................................
Finished in 1.056509s, 49.2187 runs/s, 90.8653 assertions/s.
45 runs, 73 assertions, 0 failures, 0 errors, 0 skips

如果所有测试都通过,那就值得庆祝一下;如果有错误或失败,需要仔细检查代码,与参考代码对比,查看控制台的错误信息来定位问题。

2. 调试应用程序

2.1 调试模板中的问题

有时,我们会遇到一些难以定位的问题。例如,在提交新故事后,故事页面抛出异常,无法显示故事。为了调试这个问题,需要进行以下操作:
1. 设置有问题的应用版本
- 从代码存档中复制 readit-debug-01 文件夹,放在现有 readit 应用文件夹旁边。
- 进入 readit-debug-01 文件夹,运行 rails db:migrate 执行迁移。
- 使用 rails s 启动应用。
- 打开 Rails 控制台( rails c ),添加新用户:

User.create(name: "Glenn Goodrich", email: "glenn.goodrich@sitepoint.com", password: "password", password_confirmation: "password")
- 登录并添加新故事,例如命名为 "All About Debuggers"。
- 访问 `http://localhost:3000/stories/1-all-about-debuggers`。
  1. 分析错误信息 :错误信息显示 undefined method 'name' for nil:NilClass ,这表明在 show.html.erb 模板中尝试对 nil 对象调用 name 方法。错误代码如下:
18: <p class="submitted_by">
19:   Submitted by:
20:   <span><%= link_to @story.user.name, @story.user %></span>
21: </p>
22: <p>
23:   <%= link_to @story.link, @story.link %>
  1. 确认问题 :修改 show.html.erb 模板,检查 @story.user 的类:
<p class="submitted_by">
  Submitted by:
  <%= @story.user.class %>
  <span><%# link_to @story.user.name, @story.user %></span>
</p>

重新加载页面,发现 @story.user NilClass
4. 查找原因 :恢复 show.html.erb 模板的修改,在 new.html.erb 模板中添加 debug 语句:

<% if @story.errors.any? %>
  ⋮ error HTML…
<% end %>
<%= debug @current_user %>
<%= form_for @story do |f| %>
  ⋮ form HTML…
<% end %>

通过 debug 输出的 YAML 表示可以确认 @current_user 是一个有效的用户对象。
5. 使用 Web Console :在 new 控制器动作中添加 console 调用:

def new
  console
  @story = Story.new
end

刷新页面,会出现一个类似终端的 >> 提示符,可以在其中执行 Ruby 命令,检查变量的值。
6. 定位问题根源 :查看 StoriesController create 动作:

def create
  @story = Story.new story_params
  # @story = @current_user.stories.build story_params
  ⋮ method body…
end

这里直接使用 Story 类创建新故事,而没有通过 @current_user 对象的关联,导致新提交的故事没有分配用户。同时,在 app/models/story.rb 中设置了 belongs_to :user, optional: true 。运行功能测试( rails test:controllers )会发现测试失败,这也证明了测试的重要性。

2.2 调试更复杂的问题

有时,测试套件通过,但应用仍然存在问题。例如,新提交的故事描述在最终页面中缺失。
1. 运行测试套件

$ rails test

测试结果显示所有测试都通过,但问题仍然存在。
2. 使用 byebug 调试
- 在 app/controllers/stories_controller.rb create 动作中添加 byebug 关键字:

def create
  @story = @current_user.stories.build story_params
  if @story.save
    byebug
    flash[:notice] = 'Story submission succeeded'
    redirect_to stories_path
  else
    render action: 'new'
  end
end
- 提交新故事时,浏览器会“挂起”,表示 `byebug` 已启动。
- **byebug 命令**:
命令 描述
where 显示执行栈的跟踪信息,类似于应用抛出异常时的显示
info breakpoints 显示执行栈的跟踪信息
break byebug 外壳中设置新的断点
delete 删除现有的断点
continue 离开当前调试器外壳,继续执行应用,直到遇到下一个断点
irb 在当前执行点调用交互式 Ruby 解释器
list 显示当前执行点周围的代码片段
methods 分别探索可用的类方法和实例方法
next/step 逐行执行代码, next 跳过下一行, step 进入下一行
var all/global/const all 显示当前上下文中的所有变量及其值, global 显示全局变量, const 显示常量
quit 退出调试器,如果从命令行调用,也会退出应用服务器,使用 finish 退出当前调试会话
- 定位问题 :使用 list 命令查看当前执行位置,检查 @story.description params[:story][:description] 都返回 nil 。查看完整的 params 哈希,发现 description 存在于 params[:description] 中,而不是 params[:story] 中。查看表单模板 app/views/stories/new.html.erb ,发现使用了错误的表单字段助手:
# Wrong:
<p>
  description:<br />
  <%= text_area_tag :description %>
</p>

应该使用:

# Right:
<p>
  description:<br />
  <%= f.text_area :description %>
</p>
  1. 探索 byebug 的高级功能
    • byebug 语句移到 VotesController create 动作中:
def create
  byebug
  @story = Story.find(params[:story_id])
  @story.votes.create(user: @current_user)
  respond_to do |format|
    format.html { redirect_to @story, notice: 'Vote was successfully create' }
    format.js
  end
end
- 使用 `next` 命令逐行执行代码,使用 `methods` 命令探索对象的方法。
- **设置断点**:可以在执行过程中手动设置断点,指定文件名和行号或类名和方法名。例如,在 `VotesController` 的 `create` 动作中设置断点。

2.3 调试流程总结

graph TD;
    A[遇到问题] --> B[分析错误信息];
    B --> C[确认问题所在];
    C --> D[使用调试工具];
    D --> E[定位问题根源];
    E --> F[修复问题];
    F --> G[再次测试];
    G --> H{测试是否通过};
    H -- 是 --> I[完成调试];
    H -- 否 --> A;

在开发过程中,测试和调试是必不可少的环节。通过合理使用测试套件和调试工具,可以快速定位和解决问题,提高应用的质量和性能。

3. 测试的重要性

在前面的调试过程中,我们已经看到了测试的重要性。当代码出现问题时,完善的测试用例能够帮助我们快速定位问题。例如,在调试故事用户关联问题时,运行功能测试( rails test:controllers )揭示了测试失败,明确指出新故事提交时没有存储当前用户。以下是测试失败的示例:

$ rails test:controllers
Run options: --seed 38543
# Running:
...............F
Failure:
StoriesControllerTest#test_stores_user_with_story [Usersggoodrich/projects/
debug-01testcontrollers/stories_controller_test.rb:106]:
--- expected
+++ actual
@@ -1 +1 @@
-#
<User id: 61347656, password_digest: "$2a$04$YF6ypVtUFIzFiJCgZNkCI.4GIn/OuD
07-29 12:54:34", updated_at: "2016-07-29 12:54:34">
+nil
bin/rails test test/controllers/stories_controller_test.rb:99
................
Finished in 1.915820s, 16.7030 runs/s, 29.2303 assertions/s.
32 runs, 56 assertions, 1 failures, 0 errors, 0 skips

从这个例子可以看出,如果代码从一开始就有完善的测试覆盖,就能轻松、高效地发现代码中的错误。

4. 不同调试工具的比较

在调试过程中,我们使用了多种调试工具,如 debug 语句、 web_console byebug 。下面对它们进行比较:
| 调试工具 | 优点 | 缺点 | 使用场景 |
| ---- | ---- | ---- | ---- |
| debug 语句 | 简单易用,能直接在浏览器中输出对象的 YAML 表示,方便查看对象信息 | 每次查看信息都需要刷新页面,不够灵活 | 快速查看某个对象的基本信息,如 @current_user |
| web_console | 可以在页面上直接创建 Rails 控制台,在页面上下文中执行任意 Ruby 代码,无需刷新页面 | 只能在页面上使用,对于复杂的调试场景可能不够强大 | 快速检查页面上下文中的变量值,如 @current_user session[:user_id] 等 |
| byebug | 功能强大,提供了丰富的命令,如设置断点、逐行执行代码、查看执行栈等,能深入探索应用的执行过程 | 学习成本相对较高,需要掌握一些命令 | 调试复杂的问题,如代码执行流程、变量值的变化等 |

5. 调试的最佳实践

5.1 养成编写测试用例的习惯

从开发的一开始就编写完善的测试用例,确保代码的每一个功能都有相应的测试覆盖。这样在代码修改后,能够快速发现问题,避免引入新的错误。

5.2 合理使用调试工具

根据问题的复杂程度和具体情况,选择合适的调试工具。对于简单的问题,可以先使用 debug 语句或 web_console 进行初步排查;对于复杂的问题,再使用 byebug 进行深入调试。

5.3 分析错误信息

当遇到问题时,首先仔细分析错误信息,从中获取有用的线索。错误信息通常会指出问题所在的文件和行号,以及可能的原因。

5.4 逐步排查问题

按照一定的步骤逐步排查问题,从宏观到微观,从整体到局部。例如,先确认问题的大致范围,再深入到具体的代码片段进行分析。

5.5 记录调试过程

在调试过程中,记录下遇到的问题、采取的调试步骤和最终的解决方案。这样不仅有助于自己总结经验,也方便后续的维护和参考。

6. 总结

在 Rails 应用开发中,调试和测试是确保应用质量和性能的关键环节。通过合理使用测试套件和调试工具,如 debug 语句、 web_console byebug ,我们能够快速定位和解决问题。以下是整个调试和测试过程的总结流程图:

graph LR;
    A[开发代码] --> B[编写测试用例];
    B --> C[运行测试套件];
    C --> D{测试是否通过};
    D -- 是 --> E[部署应用];
    D -- 否 --> F[调试问题];
    F --> G[分析错误信息];
    G --> H[使用调试工具定位问题];
    H --> I[修复问题];
    I --> B;

在实际开发中,我们应该养成编写测试用例的习惯,合理使用调试工具,遵循调试的最佳实践,不断提高自己的调试和测试能力,从而开发出高质量、高性能的 Rails 应用。同时,要注意不同调试工具的特点和适用场景,根据具体问题选择最合适的工具进行调试。希望这些内容能帮助你在 Rails 应用开发中更加得心应手。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值