26、Readit 功能测试与 Rails 插件使用指南

Readit 功能测试与 Rails 插件使用指南

1. Readit 功能测试

在 Readit 应用中,为确保各项功能的正常运行,进行了一系列的测试。

1.1 关联投票测试

首先是关联投票测试,代码如下:

test "voted on association" do
  assert_equal [ stories(:one) ],
  users(:glenn).stories_voted_on
end

此测试依赖于固定数据,用于断言测试用户投票的故事列表是否与预期一致。

1.2 故事控制器测试

在故事控制器(StoriesController)中,添加了许多需要测试的功能,测试相对复杂。
- 故事索引页面测试
- 为确认故事列表操作(索引和回收站)能从数据库中选取正确的记录,在 test/fixtures/stories.yml 中添加新故事:

promoted:
  name: What is a Debugger?
  link: http://en.wikipedia.org/wiki/Debugger/
  user: john
  votes_count: 5
- 修改现有测试并添加新测试以确保模板正确渲染:
class StoriesControllerTest < ActionDispatch::IntegrationTest
  # 其他测试方法...
  test "gets stories" do
    get stories_path
    assert_response :success
    assert response.body.include?(stories(:promoted).name)
  end
  test "gets bin" do
    get bin_stories_path
    assert_response :success
    assert response.body.include?(stories(:two).name)
  end
  # 其他测试方法...
end

这两个测试调用各自的操作,检查请求是否成功响应,并确认是否渲染了合适的故事。
- 路由配置测试
添加测试以确认路由配置更改是否正常工作:

test "story index is default" do
  assert_recognizes({ controller: "stories",
  action: "index" }, "/")
end

该断言确认对根路径“/”的请求会被路由到 StoriesController 的索引操作。
- 页面标题测试

test "shows story on index" do
  get stories_path
  assert_select 'h2', 'Showing 1 frontpage story'
  assert_select 'div#content div.story', count: 1
end
test "show stories in bin" do
  get bin_stories_path
  assert_select 'h2', 'Showing 2 upcoming stories'
  assert_select 'div#content div.story', count: 2
end

这些测试检查索引操作的视图,确认标题标签包含正确的标题和预期数量的故事。
- 故事提交表单测试

test "new shows new form" do
  login_user
  get :new
  assert_select 'form p', count: 3
end

此测试检查故事提交表单中的 <p> 元素数量是否符合预期。
- 故事显示页面测试

test "show story vote elements" do
  login_user
  get story_path(stories(:one))
  # 方法体...
end
test "does not show vote button if not logged in" do
  get story_path(stories(:one))
  assert_select 'div#vote_link', false
end

这些测试处理未登录用户看不到投票按钮的情况。
- 导航菜单测试

test "show navigation menu" do
  get stories_path
  assert_select 'ul#navigation li', 3
end

由于导航菜单添加了一个项目,所以检查列表项数量是否为 3。
- 故事提交者链接文本测试

test "show story submitter" do
  get story_path(stories(:one))
  assert_select 'p.submitted_by span a', 'Glenn Goodrich'
end

此测试确保故事页面上的故事提交者链接到提交者的用户页面。

1.3 投票控制器测试

由于投票程序修改为仅对登录用户可用,需要修改现有测试并添加新测试:

test "stores user with vote" do
  post story_votes_path(stories(:two))
  stories(:two).reload
  assert_equal users(:glenn), stories(:two).votes.last.user
end

该测试确认投票操作会存储当前用户与提交的投票。

1.4 用户控制器测试

为覆盖用户控制器(UsersController)中用户页面的功能,添加了三个测试:

class UsersControllerTest < ActionController::TestCase
  test "show user" do
    get user_path(users(:glenn))
    assert_response :success
    assert response.body.include?(users(:glenn).name)
  end
  test "show submitted stories" do
    get user_path(users(:glenn))
    assert_select 'div#stories_submitted div.story', count: 2
  end
  test "show stories voted on" do
    get user_path(users(:glenn))
    assert_select 'div#stories_voted_on div.story', count: 1
  end
end

这些测试确认显示操作能找到正确的用户,并在页面上正确显示用户提交的故事和投票历史。

1.5 完整测试套件运行

完成所有测试添加后,运行完整测试套件:

$ rails test

测试结果显示,所有测试均通过,表明 Readit 应用状态良好。

2. Rails 插件

Rails 插件是可以添加到应用中以扩展其功能的组件。

2.1 插件概述

插件可用于扩展 ActiveRecord 功能、提供辅助方法、引入新的模板引擎等。可以通过在 Rubygems 或 Ruby Toolbox 网站上搜索“Rails”来找到现有的插件。插件以 gem 形式分发,可通过将其添加到 Gemfile 并运行 bundle install 来引入应用。

2.2 标签功能插件:acts - as - taggable - on

为了给 Readit 应用添加标签功能,选择使用 acts - as - taggable - on 插件。

  • 插件历史 :该插件有一段发展历史,最初 David Heinemeier Hansson 开发了 acts_as_taggable 作为概念验证,后被弃用。Jonathan Viney 开发了 acts_as_taggable_on_steroids ,最终 Michael Bleigh 形成了 acts - as - taggable - on 并持续开发。
  • acts_as_* 命名约定 :在 Rails 插件仓库中,有许多 acts_as_* 形式的功能扩展,这些扩展能让模型具备特定功能,通常只需一行代码即可启用。例如 acts_as_list 可使对象位于扁平列表中, acts_as_tree 可创建复杂的树状系统。而 acts - as - taggable - on 能让模型可标签化,它自带 ActsAsTaggableOn::Tag 模型类,并能将以空格分隔的标签列表解析为单独的模型对象。
  • 命名空间安全措施 Tag 类被命名空间为 ActsAsTaggableOn ,这是 Ruby 社区的最佳实践,可避免不同 gem 或库中的类名冲突。
2.3 安装 acts - as - taggable - on 插件

安装步骤如下:
1. 进入应用根目录,在 Gemfile 中添加以下内容:

gem "acts-as-taggable-on", "~> 4.0"

~> 表示希望使用 4.x 系列的任何版本。
2. 运行以下命令安装插件:

$ bundle install

安装完成后,会有来自 acts - as - taggable - on gem 的安装后消息。

2.4 创建插件迁移

为了让用户能给提交的故事添加标签,需要为故事模型添加可标签化功能。由于插件使用了新模型,需要创建迁移来创建新表。
- 生成迁移文件

$ rails acts_as_taggable_on_engine:install:migrations

此命令会将五个迁移文件复制到 db/migrate 目录,这些文件将创建 acts - as - taggable - on 使用的表和数据库索引。
- 迁移代码

class ActsAsTaggableOnMigration < ActiveRecord::Migration
  def self.up
    create_table :tags do |t| 
      t.string :name
    end
    create_table :taggings do |t|
      t.references :tag
      # 确保创建的列足够长以存储所需的类名
      t.references :taggable, polymorphic: true
      t.references :tagger, polymorphic: true
      # 限制长度以防止 MySQL MyISAM 表类型的索引长度错误
      t.string :context, limit: 128
      t.datetime :created_at
    end
    add_index :taggings, :tag_id
    add_index :taggings, [:taggable_id, :taggable_type, :context]
  end

  def self.down
    drop_table :taggings
    drop_table :tags
  end
end

该迁移创建了 tags taggings 表, tags 表存储标签名称, taggings 表存储标签与被标签对象之间的映射关系。其中 polymorphic 表示多态,允许一个表与多个不同类型的模型关联。在给故事模型添加 acts - as - taggable - on 功能之前,需要应用刚刚生成的迁移。

总结

通过对 Readit 应用进行全面的功能测试,确保了各项功能的稳定性。同时,借助 Rails 插件 acts - as - taggable - on ,可以为应用添加标签功能,进一步扩展应用的功能。在后续开发中,可以继续添加更多功能,并不断完善测试套件。

以下是一个简单的 mermaid 流程图,展示了安装 acts - as - taggable - on 插件的流程:

graph LR
    A[进入应用根目录] --> B[在 Gemfile 中添加插件]
    B --> C[运行 bundle install]
    C --> D[生成迁移文件]
    D --> E[应用迁移]
步骤 操作 代码示例
1 进入应用根目录 cd 应用根目录路径
2 在 Gemfile 中添加插件 gem “acts-as-taggable-on”, “~> 4.0”
3 运行 bundle install bundle install
4 生成迁移文件 rails acts_as_taggable_on_engine:install:migrations
5 应用迁移 rails db:migrate

Readit 功能测试与 Rails 插件使用指南

3. 应用 acts - as - taggable - on 插件到 Readit

在完成 acts - as - taggable - on 插件的安装和迁移后,接下来需要将其应用到 Readit 的故事模型中,让用户能够为故事添加标签。

3.1 使故事模型可标签化

要让故事模型支持标签功能,需要在 Story 模型文件中添加相应的代码。打开 app/models/story.rb 文件,添加如下代码:

class Story < ApplicationRecord
  acts_as_taggable_on :tags
end

acts_as_taggable_on :tags 这行代码启用了故事模型的标签功能,允许用户为故事添加标签。

3.2 更新故事提交表单

为了让用户能够在提交故事时添加标签,需要更新故事提交表单。打开 app/views/stories/_form.html.erb 文件,添加一个标签输入字段:

<%= form.label :tag_list, "Tags (separated by spaces or commas)" %>
<%= form.text_field :tag_list %>

这个输入字段允许用户输入以空格或逗号分隔的标签列表。

3.3 处理标签数据

StoriesController 中,需要处理用户提交的标签数据。打开 app/controllers/stories_controller.rb 文件,更新 create update 方法,确保标签数据被正确保存:

class StoriesController < ApplicationController
  def create
    @story = Story.new(story_params)
    if @story.save
      redirect_to @story, notice: 'Story was successfully created.'
    else
      render :new
    end
  end

  def update
    if @story.update(story_params)
      redirect_to @story, notice: 'Story was successfully updated.'
    else
      render :edit
    end
  end

  private

  def story_params
    params.require(:story).permit(:name, :link, :user_id, :tag_list)
  end
end

story_params 方法中,添加了 :tag_list 字段,确保标签数据能够被正确传递和保存。

3.4 显示故事标签

在故事显示页面,需要显示故事的标签。打开 app/views/stories/show.html.erb 文件,添加如下代码:

<p>
  <strong>Tags:</strong>
  <%= @story.tag_list.join(', ') %>
</p>

这行代码将故事的标签列表以逗号分隔的形式显示在页面上。

4. 测试标签功能

为了确保标签功能正常工作,需要编写相应的测试用例。

4.1 测试故事创建时的标签保存

test/controllers/stories_controller_test.rb 文件中,添加如下测试用例:

test "creates story with tags" do
  login_user
  post stories_path, params: { story: { name: 'Test Story', link: 'http://example.com', tag_list: 'ruby, rails' } }
  assert_redirected_to story_path(assigns(:story))
  story = assigns(:story)
  assert_equal ['ruby', 'rails'], story.tag_list
end

这个测试用例模拟用户创建一个带有标签的故事,并验证标签是否被正确保存。

4.2 测试故事更新时的标签更新

同样在 test/controllers/stories_controller_test.rb 文件中,添加如下测试用例:

test "updates story with new tags" do
  login_user
  story = stories(:one)
  patch story_path(story), params: { story: { tag_list: 'newtag1, newtag2' } }
  assert_redirected_to story_path(story)
  story.reload
  assert_equal ['newtag1', 'newtag2'], story.tag_list
end

这个测试用例模拟用户更新一个故事的标签,并验证标签是否被正确更新。

5. 进一步扩展 Readit

虽然已经为 Readit 添加了标签功能,但还有许多其他功能可以进一步扩展。

5.1 用户注册和登录功能

可以添加用户注册和登录功能,让用户能够创建自己的账户并登录。可以使用 Devise 等宝石来实现这一功能。具体步骤如下:
1. 在 Gemfile 中添加 Devise 宝石:

gem 'devise'
  1. 运行 bundle install 安装宝石。
  2. 生成 Devise 配置:
rails generate devise:install
  1. 生成用户模型:
rails generate devise User
  1. 运行迁移:
rails db:migrate
  1. 在视图和控制器中添加相应的注册和登录页面及逻辑。
5.2 故事评论功能

可以添加故事评论功能,让用户能够对故事发表评论。可以创建一个 Comment 模型,并在故事显示页面添加评论表单和评论列表。具体步骤如下:
1. 生成 Comment 模型:

rails generate model Comment content:text story:references user:references
  1. 运行迁移:
rails db:migrate
  1. Story 模型中关联评论:
class Story < ApplicationRecord
  has_many :comments
end
  1. User 模型中关联评论:
class User < ApplicationRecord
  has_many :comments
end
  1. 在故事显示页面添加评论表单和评论列表:
<h2>Comments</h2>
<% @story.comments.each do |comment| %>
  <p><%= comment.content %></p>
  <p>By <%= comment.user.name %></p>
<% end %>

<%= form_with(model: [@story, @story.comments.build], local: true) do |form| %>
  <%= form.label :content %>
  <%= form.text_area :content %>
  <%= form.submit %>
<% end %>
5.3 投票限制功能

可以添加投票限制功能,确保用户只能对每个故事投票一次。可以在 Vote 模型中添加唯一约束,并在投票时进行检查。具体步骤如下:
1. 在 Vote 模型中添加唯一约束:

class Vote < ApplicationRecord
  validates_uniqueness_of :user_id, scope: :story_id
end
  1. VotesController 中添加投票检查逻辑:
class VotesController < ApplicationController
  def create
    @story = Story.find(params[:story_id])
    if @story.votes.where(user_id: current_user.id).exists?
      redirect_to @story, alert: 'You have already voted for this story.'
    else
      @vote = @story.votes.create(user: current_user)
      redirect_to @story, notice: 'Vote cast successfully.'
    end
  end
end

总结

通过对 Readit 应用进行功能测试和添加 acts - as - taggable - on 插件,我们不仅确保了应用的稳定性,还为应用添加了强大的标签功能。同时,我们还探讨了如何进一步扩展 Readit,如添加用户注册和登录、故事评论和投票限制等功能。在开发过程中,要不断完善测试套件,确保新功能的正确性和稳定性。

以下是一个 mermaid 流程图,展示了扩展 Readit 功能的步骤:

graph LR
    A[添加标签功能] --> B[添加用户注册和登录功能]
    B --> C[添加故事评论功能]
    C --> D[添加投票限制功能]
扩展功能 操作步骤
添加标签功能 1. 使故事模型可标签化;2. 更新故事提交表单;3. 处理标签数据;4. 显示故事标签;5. 编写测试用例
添加用户注册和登录功能 1. 添加 Devise 宝石;2. 生成 Devise 配置;3. 生成用户模型;4. 运行迁移;5. 添加注册和登录页面及逻辑
添加故事评论功能 1. 生成 Comment 模型;2. 运行迁移;3. 关联评论模型;4. 添加评论表单和列表
添加投票限制功能 1. 添加唯一约束;2. 添加投票检查逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值