How to create a test user in test/fixtures/user.ym

2019-07-13 08:42发布

问题:

As you can see from the codes below, I already created a user in users.yml, included the devise's helper for integration test in test_helper.rb (that's why I was able to use the sign_in method - based on Devise's README), and have a passing integration test in site_layout_test.rb.

My question is, when I tried to comment-out the email, encrypted_password, and created_at params of user john in users.yml, I still have a passing test but my newbie mind tells me that I should have a failing test now since user john is now not a valid user.

What's happening here? Why am I still having a passing test?

By the way, this is the link that helped me how to create a user in users.yml

test/fixtures/users.yml

john:
  name: John Rockefeller
  email: john@rockefeller.com
  encrypted_password: <%= Devise::Encryptor.digest(User, 'password') %>
  created_at: <%= Time.zone.now %>

test_helper.rb

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
  include ApplicationHelper
  include Devise::Test::IntegrationHelpers
end

test/integration/site_layout_test.rb

require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest
  def setup
    @user = users(:john)
  end

  test "layout links" do
    # Not signed in
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", new_user_session_path, count: 2
    assert_select "a[href=?]", new_user_registration_path
    get new_user_registration_path
    assert_template 'devise/registrations/new'
    assert_select "title", full_title("Sign up")
    get new_user_session_path
    assert_template 'devise/sessions/new'
    assert_select "title", full_title("Sign in")
    # Signed in
    sign_in @user
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", new_user_session_path, count: 0
    assert_select "a[href=?]", new_user_registration_path, count: 0
    assert_select "a[href=?]", edit_user_registration_path
    assert_select "a[href=?]", destroy_user_session_path
    get edit_user_registration_path
    assert_template 'devise/registrations/edit'
    assert_select "title", full_title(@user.name)
  end
end

EDIT: SOLVED! My new site_layout_test.rb below:

require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest
  def setup
    @user = users(:john)
  end

  test "non-signed in user layout links" do
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", new_user_session_path, count: 2
    assert_select "a[href=?]", new_user_registration_path
  end

  test "signed in user layout links" do
    get new_user_session_path
    assert_template 'devise/sessions/new'
    post user_session_path, params: { user: { email: @user.email, password: 'password' } }
    assert_not flash.empty?
    assert_redirected_to root_path
    follow_redirect!
    assert_template 'static_pages/home'
    assert_select "a[href=?]", new_user_session_path, count: 0
    assert_select "a[href=?]", new_user_registration_path, count: 0
    assert_select "a[href=?]", edit_user_registration_path
    assert_select "a[href=?]", destroy_user_session_path
  end

  test "page title" do
    get new_user_registration_path
    assert_template 'devise/registrations/new'
    assert_select "title", full_title("Sign up")
    get new_user_session_path
    assert_template 'devise/sessions/new'
    assert_select "title", full_title("Sign in")
  end
end

回答1:

There are two things you need to keep in mind.

First, fixtures are inserted directly into the database. The corresponding model is not instantiated. As a consequence, it's possible to insert values which would make model-level validations fail.

Second, sign_in simply sets the user ID in the session (you can think of it as session[:user_id] = @user.id). It performs no authentication. It should be used when testing a feature other than authentication (e.g. posting as a user on a forum). It skips the whole request-response cycle related to authentication and lets you go straight to the controller and action you want to test.

In order to test authentication you should fire a POST request against new_sessions_path (please substituted the route names you use in your app):

post new_sessions_path, params: { email: '...', password: '...' }

Last but not least, I recommend you split your test into many smaller tests. Especially that you named it layout links but you test sign in which is confusing.