基于rails的schedule网站开发(15):学习如何测试

1 篇文章 0 订阅

abstract:

登录-失败!:

1. <9.1.3>”编辑失败“测试

  test "unsuccessful edit" do
    get edit_user_path(@user)
    patch user_path(@user), user: { name:  '',
                                    email: '',
                                    password:              'foo',
                                    password_confirmation: 'bar' }
    assert_template 'users/edit'
  end

测试结果:

moses@moses-virtual-machine:~/projects/compass_v1.1$ bundle exec rake test
Started

 FAIL["test_unsuccessful_edit", UsersEditTest, 0.604847775]
 test_unsuccessful_edit#UsersEditTest (0.60s)
        expecting <"users/edit"> but rendering with <[]>
        test/integration/users_edit_test.rb:17:in `block in <class:UsersEditTest>'

  14/14: [=================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.70103s
14 tests, 37 assertions, 1 failures, 0 errors, 0 skips

2. <9.1.4>”编辑成功“测试

test "successful edit" do
    get edit_user_path(@user)
    name  = "Foo Bar"
    email = "foo@bar.com"
    patch user_path(@user), user: { name:  name,
                                    email: email,
                                    password:              "",
                                    password_confirmation: "" }
    assert_not flash.empty?
    assert_redirected_to @user
    @user.reload
    assert_equal @user.name,  name
    assert_equal @user.email, email
  end

测试结果:

moses@moses-virtual-machine:~/projects/compass_v1.1$ bundle exec rake test
Started

 FAIL["test_successful_edit", UsersEditTest, 0.238506237]
 test_successful_edit#UsersEditTest (0.24s)
        Expected response to be a redirect to <http://www.example.com/users/762146111> but was a redirect to <http://www.example.com/login>.
        Expected "http://www.example.com/users/762146111" to be === "http://www.example.com/login".
        test/integration/users_edit_test.rb:19:in `block in <class:UsersEditTest>'

  14/14: [=================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.67668s
14 tests, 39 assertions, 1 failures, 0 errors, 0 skips

错误1和错误2涉及到8.4.6节的log_in_as方法

注册信息有效性测试:
1. 邮件格式测试
test/models/user_test.rb

require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end
  .
  .
  .
  test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
    end
  end
end

使用%w[]创建“邮箱地址”的数组
assert @user.valid?, "#{valid_address.inspect} should be valid"
中inspect 方法,返回被调用对象的字符串字面量表现形式
例如:

>> puts (1..5).to_a            # 把值域转换成数组
1
2
3
4
5
>> puts (1..5).to_a.inspect    # 输出数组的字面量形式
[1, 2, 3, 4, 5]
>> puts :name, :name.inspect
name
:name
>> puts "It worked!", "It worked!".inspect
It worked!
"It worked!"

2. 唯一性验证
拒绝重复电子邮件地址的测试 RED
test/models/user_test.rb

require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end
  .
  .
  .
  test "email addresses should be unique" do
    duplicate_user = @user.dup
    @user.save
    assert_not duplicate_user.valid?
  end
end

这里使用@user.dup 方法创建一个和 @user 的电子邮件地址一样的用户对象,然后保存 @user,因为数据库中的 @user 已经占用了这个电子邮件地址,所有 duplicate_user 对象无效。

注册测试:

生成测试文件:
$ rails generate integration_test users_signup
进行测试:
$ bundle exec rake test

1. 注册失败的测试

第一个测试文件:
test/integration/users_signup_test.rb

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, user: { name:  "",
                               email: "user@invalid",
                               password:              "foo",
                               password_confirmation: "bar" }
    end
    assert_template 'users/new'
  end
end

get 方法访问注册页面
get signup_path

用assert_no_difference方法判断提交的数据是否改变
assert_no_difference 'User.count'
即,User.count有没有增加,借此来反应用户注册有没有成功。

2. 注册成功的测试
第二个测试文件:
test/integration/users_signup_test.rb

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest
  .
  .
  .
  test "valid signup information" do
    get signup_path
    name     = "Example User"
    email    = "user@example.com"
    password = "password"
    assert_difference 'User.count', 1 do
      post_via_redirect users_path, user: { name:  name,
                                            email: email,
                                            password:  password,
                                            password_confirmation: password }
    end
    assert_template 'users/show'
  end
end

对比第一个测试文件

assert_no_difference 'User.count' do
  post users_path, ...
end

第二个测试文件中的assert_difference方法

assert_difference 'User.count', 1 do
  post_via_redirect users_path, ...
end

指的是观察“指定变化的数量”,第二个参数可选,这里是1。

post_via_redirect 方法,目的是提交数据后继续跟踪重定向

登录测试:

生成测试文件:
$ rails generate integration_test users_login
测试指定文件:指定 TEST 参数和文件的完整路径,演示如何只运行一个测试文件
$ bundle exec rake test TEST=test/integration/users_login_test.rb

1. 注册失败的测试
捕获继续显示闪现消息的测试
test/integration/users_login_test.rb

require 'test_helper'

class UsersLoginTest < ActionDispatch::IntegrationTest

  test "login with invalid information" do
    get login_path
    assert_template 'sessions/new'
    post login_path, session: { email: "", password: "" }
    assert_template 'sessions/new'
    assert_not flash.empty?
    get root_path
    assert flash.empty?
  end
end

assert_template 方法检查首页是否使用正确的视图渲染
assert_not 方法确认得到的用户对象是无效的

2. 测试布局中的变化

测试步骤:
1. 访问登录页面;
2. 通过 post 请求发送有效的登录信息;
3. 确认登录链接消失了;
4. 确认出现了退出链接;
5. 确认出现了资料页面链接。

为了检查这些变化,在测试中要登入已经注册的用户,也就是说数据库中必须有一个用户。Rails 默认使用“固件”实现这种需求。固件是一种组织数据的方式,这些数据会载入测试数据库。

目前,我们只需要一个用户,它的名字和电子邮件地址应该是有效的。因为我们要登入这个用户,所以还要提供正确的密码,和提交给会话控制器中 create 动作的密码比较。

要先理解:
password_digest
密码摘要使用 bcrypt 生成(通过 has_secure_password 方法),所以固件中的密码摘要也要使用这种方法生成。查看安全密码的源码后,我们发现生成摘要的方法是:

BCrypt::Password.create(string, cost: cost)

其中,string 是要计算哈希值的字符串;cost 是“耗时因子”,决定计算哈希值时消耗的资源。耗时因子的值越大,由哈希值破解出原密码的难度越大。这个值对生产环境的安全防护很重要,但在测试中我们希望 digest 方法的执行速度越快越好。安全密码的源码中还有这么一行代码:

cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost

这行代码的作用是严格实现前面的分析:在测试中耗时因子使用最小值,在生产环境则使用普通(最大)值。

digest 方法可以放在几个不同的地方,这里放在 user.rb 中。

# 返回指定字符串的哈希摘要
  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end

定义好 digest 方法后,我们可以创建一个有效的用户固件了

测试用户登录所需的固件
test/fixtures/users.yml

michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>

使用
<%= User.digest('password') %>
创建密码摘要

我们虽然定义了 has_secure_password 所需的 password_digest 属性,但有时也需要使用密码的原始值。可是,在固件中无法实现,如果添加 password 属性,Rails 会提示数据库中没有这个列(确实没有)。所以,我们约定固件中所有用户的密码都一样,即 ‘password’。

创建了一个有效用户固件后,在测试中可以使用下面的方式获取这个用户:

user = users(:michael)

测试使用有效信息登录的情况
test/integration/users_login_test.rb

require 'test_helper'

class UsersLoginTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end
  .
  .
  .
  test "login with valid information" do
    get login_path
    post login_path, session: { email: @user.email, password: 'password' }
    # assert_redirected_to @user 检查重定向的地址是否正确;
    assert_redirected_to @user
    # follow_redirect! 访问重定向的目标地址。
    follow_redirect!
    assert_template 'users/show'
    # 测试login_path链接数为0
    assert_select "a[href=?]", login_path, count: 0
    # 测试logout_path链接数为1
    assert_select "a[href=?]", logout_path
    assert_select "a[href=?]", user_path(@user)
  end
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值