我根本不明白这一点:
简而言之,这个
it "should assign @user_friendship_1 to the instance variable #|@user_friendships|" do
var = "something"
ap @user_friendship_1
var.should == @user_friendship_1
end
导致了这个奇怪的错误:
.#<UserFriendship:0x000001031fb6f8> {
:id => 1,
:friend_id => 2,
:user_id => 1,
:created_at => Tue, 10 Dec 2013 05:56:54 UTC +00:00,
:updated_at => Tue, 10 Dec 2013 05:56:54 UTC +00:00,
:state => "accepted"
}
....
Failures:
1) UserFriendshipsController: When four valid User instances exist, @user_1, @user_2, @user_3, @user_4, and when logged in as @user_, and when a UserFriendship, @user_friendship_1, is joining @user_1 with @user_2, a PATCH request to the #edit action with the :id of @user_friendship_1 should assign @user_friendship_1 to the instance variable #|@user_friendship_1|
Failure/Error: assigns(:dfsdf).should == @user_frienship_1
expected: nil
got: "something" (using ==)
我的意思是什么? ap
证明@ user_friendship_1是一个哈希值,并且在期望值内的nil
处评估完全相同的变量?究竟是什么?
规格:
require 'spec_helper'
require 'ap'
describe UserFriendshipsController do
context "\b: When four valid User instances exist, @user_1, @user_2, @user_3, @user_4" do
before do
@user_1 = FactoryGirl.create(:user_with_all_valid)
@user_1.reload
@user_2 = FactoryGirl.create(:user_with_all_valid_two)
@user_2.reload
@user_3 = FactoryGirl.create(:user_with_all_valid_three)
@user_3.reload
@user_4 = FactoryGirl.create(:user_with_all_valid_four)
@user_4.reload
end
context "\b, and when not logged in" do
before do
end
context "\b, a PUT request to the #accept action" do
before do
put :accept, id: 1
end
it "should redirect to the login page" do
response.response_code.should == 302
response.should be_redirect
response.should redirect_to new_user_session_path
end
end
end
context "\b, and when logged in as @user_1" do
before do
sign_in @user_1
end
context "\b, and when a UserFriendship, @user_friendship_1, is joining @user_1 with @user_2" do
before do
@user_friendship_1 = FactoryGirl.create(:pending_user_friendship, user_id: @user_1.id, friend_id: @user_2.id)
@user_friendship_1.reload
end
it "@user_friendship_1.state should equal 'pending' by default, when it is created" do
@user_friendship_1.state.should == 'pending'
end
context "\b, a PATCH request to the #edit action with the :id of @user_friendship_1" do
before do
patch :edit, id: @user_friendship_1.id
@user_friendship_1.reload
end
it "should assign @user_friendship_1 to the instance variable #|@user_friendship_1|" do
puts "****"
ap @user_frienship_1
end
it "should assign @user_friendship_1 to the instance variable #|@user_friendship_1|" do
assigns(:dfsdf).should == @user_frienship_1
end
it "should assign @user_friendship_1 to the instance variable #|@user_friendship_1|" do
puts @user_friendships_1.inspect
assigns(:dfsdf).should_not == @user_frienship_1
end
end
context "\b, a PUT request to the #accept action with the :id of @user_friendship_1" do
before do
put :accept, id: @user_friendship_1.id
@user_friendship_1.reload
end
it "should assign @user_friendship_1 to the instance variable #|@user_friendships|" do
var = "something"
ap @user_friendship_1
var.should == @user_friendship_1
end
it "should change @user_friendship_1.state from 'pending' to 'accepted' " do
@user_friendship_1.state.should == 'accepted'
end
it "should populate the flash[:success] with the success message '' " do
flash[:success].should == "You are now friends with " + @user_2.first_name + "!"
end
it "should redirect to the show route of that friendship" do
response.should redirect_to user_friendship_path
end
end
end
end
end
工厂:
FactoryGirl.define do
factory :status_one, class: Status do
# name "Here is numerano Uno Status!"
content "This is definitely the number one status! One, as in 1!"
end
factory :user_with_all_valid, class: User do
first_name "jimmy"
last_name "Thehat"
profile_name "Jimbohatboy"
sequence (:email){ |n| "awesomedog" + n.to_s + "@hotmail.co.uk" }
password "thisisasupersecretpassword12234234"
password_confirmation "thisisasupersecretpassword12234234"
end
# look into the following:
# we can nest factories
# we can use sequences to increment email addresses and make them unique
# we can set up associations (below)
# use fresh users here, that's what'ss causing the error
factory :user_friendship_1, class: UserFriendship do
association :user, factory: :user_with_all_valid_five
# or :user_id, factory: :user_with_all_valid[id]
association :friend, factory: :user_with_all_valid_six
# or :friend_id, factory: :user_with_all_valid_two[id]
factory :pending_user_friendship do
state 'pending'
end
factory :requested_user_friendship do
state 'requested'
end
factory :accepted_user_friendship do
state 'accepted'
end
end
factory :user_with_all_valid_two, class: User do
first_name "Mattychips"
last_name "Matthews"
profile_name "Chipboy76"
email "Chips@hotmail.co.uk"
password "yeahyeahsupersecret"
password_confirmation "yeahyeahsupersecret"
end
factory :user_with_all_valid_three, class: User do
first_name "Ratty"
last_name "Excellent"
profile_name "Ratexcellent"
email "rat@hotmail.co.uk"
password "hello_987"
password_confirmation "hello_987"
end
factory :user_with_all_valid_four, class: User do
first_name "Sylvia"
last_name "Plath"
profile_name "collosus64676421"
email "collosus@987987.co.uk"
password "thisisasupersecretpassword12234234"
password_confirmation "thisisasupersecretpassword12234234"
end
end
模型:
class UserFriendship < ActiveRecord::Base
# sets the 'state' column to pending whenever a new model (UserFriendship) is created
state_machine :state, initial: :pending do
after_transition on: :accept, do: :send_accept_email
=begin
this creates an action called 'accepted!' and changes the 'state' column to 'accepted' when called
it's basically a shorthand for this method (the exclamation mark, nothing more than a practise that doesn't
change the code) is automatically added to the method name. This is because it's a potentially
dangerous bang method that we've made:
event :accept do
transition any => :accepted
end
is the same as writing:
def accept!
self.state == 'accepted'
end
=end
event :accept do
transition any => :accepted
end
state :requested
end
belongs_to :user
=begin this right here, is where the friend model comes into existance.
belongs_to :friend, class_name: 'User'
is basically a shorthand for creating a new model file, friend.rb and populating it with the same
contents as user.rb (I think..maybe just the attributes and certain associations)
=end
belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'
控制器:
class UserFriendshipsController < ApplicationController
before_filter :authenticate_user!, only: [:new, :create, :index, :accept]
def accept
# why does this need to be scoped to the current user? This does the same thing:
#
# @user_friendships = UserFriendship.find_by_id(params[:id])
#
# exactly the same result. Find out the benefit and the reasoning.
@user_friendships = current_user.user_friendships.find_by_id(params[:id])
# a shorthand for if @user_friendships.accept! == true . All methods evaluate to boolean true
# 'true' if they are successful, and false if otherwise. This way, we can do a simple statement:
if @user_friendships.accept!
flash[:success] = "You are now friends with " + @user_friendships.friend.first_name + "!"
else
flash[:error] = "Friendship between you, " + current_user.profile_name + " and " + @user_friendships.friend.first_name + "could not be created"
end
redirect_to user_friendship_path
end
def edit
@dfsdf = "cheese"
end
def index
@user_friendships = current_user.user_friendships.load
end
def new
if params[:friend_id]
@friend = User.find_by_profile_name(params[:friend_id])
@user_friendship = current_user.user_friendships.new(friend: @friend)
else
flash[:error] = "Friend required"
end
if @friend
else
flash[:notice] = "That user could not be found"
render file: 'public/404', status: 404
end
=begin
rescue ActiveRecord::RecordNotFound
flash[:notice] = "That user could not be found"
render file: 'public/404', status: 404
=end
end
def create
if params[:user_friendship][:friend_id]
@friend = User.find_by_id(params[:user_friendship][:friend_id])
logger.fatal @friend.inspect
else
end
if @friend
current_user.user_friendships.create(friend: @friend)
flash[:success] = @friend.profile_name + " added as friend!"
redirect_to profile_path(@friend.profile_name), status: 302
else
flash[:error] = "Friend required!"
redirect_to root_path, status: 302
end
end
end
spec_helper:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'ap'
def set(factory)
@user = FactoryGirl.create(factory)
end
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.include Capybara::DSL
=begin
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.after(:suite) do
# DatabaseCleaner.strategy = :transaction
# DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.clean
end
=end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# config.include RSpec::Rails::RequestExampleGroup, type: :feature
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
end
答案 0 :(得分:1)
首先,您最初引用的示例不是失败的示例。失败的样本位于“PATCH”上下文中,基于失败消息中输出的描述链。但是,该上下文中的it
块都没有将"something"
分配给var
或输出var
。
并且,感谢other answer,您可以看到示例中出现@user_frienship-1
错字:
it "should assign @user_friendship_1 to the instance variable #|@user_friendship_1|" do
assigns(:dfsdf).should == @user_frienship_1
end
由于未定义的实例变量的计算结果为nil
,因此您将遇到问题。
顺便说一下,这是为什么避免使用before
在RSpec测试中分配实例变量以支持使用let
来分配常规变量作为无效引用的一个例子。常规变量将生成错误而不是静默返回nil
。
答案 1 :(得分:0)
您在这些规范中将@user_friendship_1
错误地标记为@user_frienship_1
几次。我怀疑这可能是相关的。