我是学习RSpec的新手。我似乎不明白为什么我的测试#start method
失败了。
如果有人能向我解释一下,我将不胜感激。
我得到的错误:
CardGame
attributes
should have a name
#response method
should say hello
#start method
can only implement class methods that are defined on a class (FAILED - 1)
Failures:
1) CardGame#start method can only implement class methods that are defined on a class
Failure/Error:
def initialize(name)
@name = name
end
ArgumentError:
wrong number of arguments (given 0, expected 1)
# ./lib/CardGame.rb:4:in `initialize'
# ./spec/class_double_spec.rb:29:in `block (3 levels) in <top (required)>'
Finished in 0.01178 seconds (files took 0.30252 seconds to load)
3 examples, 1 failure
Failed examples:
rspec ./spec/class_double_spec.rb:27 # CardGame#start method can only implement class methods that are defined on a class
➜ rspec-course
class_double_spec.rb
[ruby/spec/class_double_spec.rb]
require 'spec_helper'
require 'pry'
require './lib/CardGame'
require './lib/Deck'
describe CardGame do
let(:card) { instance_double(CardGame,
name: 'poker',
response: 'hello')}
let(:deck_klass) { class_double(Deck, build: ['Ace', 'Queen']).as_stubbed_const }
context 'attributes' do
it 'should have a name' do
expect(card.name).to eq('poker')
end
end
context '#response method' do
it 'should say hello' do
allow(card).to receive(:response).and_return('hello')
expect(card.response).to eq('hello')
end
end
context '#start method' do
it 'can only implement class methods that are defined on a class' do
expect(deck_klass).to receive(:build)
card.start
expect(card.cards).to eq(['Ace', 'Queen'])
end
end
end
CardGame.rb
[ruby/lib/CardGame.rb]
class CardGame
attr_accessor :name, :cards
def initialize(name)
@name = name
end
def response
'hello'
end
def start
@cards = Deck.build
end
end
甲板.rb
[ruby/lib/Deck.rb]
class Deck
def self.build
# business logic to build cards
end
end
你一个模拟一个模拟。一个人应该严格应用的规则之一是不要模拟测试中的单元,所以代替
describe CardGame do
let(:card) { instance_double(CardGame,
name: 'poker',
response: 'hello')}
let(:deck_klass) { class_double(Deck, build: ['Ace', 'Queen']).as_stubbed_const }
context 'attributes' do
it 'should have a name' do
expect(card.name).to eq('poker')
end
end
end
做这个
describe CardGame do
let(:card) { CardGame.new(name) }
let(:name) { 'poker'}
context 'attributes' do
it 'should have a name' do
expect(card.name).to eq('poker')
end
end
end
为什么不模拟测试中的单元?
context '#response method' do
it 'should say hello' do
allow(card).to receive(:response).and_return('hello')
expect(card.response).to eq('hello')
end
end
因为在这个例子中,您只是在测试RSpec的mocking框架是否有效。简化
context '#response method' do
it 'should say hello' do
expect(card.response).to eq('hello')
end
end
最后一个例子:
context '#start method' do
it 'can only implement class methods that are defined on a class' do
expect(deck_klass).to receive(:build)
card.start
expect(card.cards).to eq(['Ace', 'Queen'])
end
end
看起来更好,模拟类不是直接测试的,而是由被测试单元(Card
(使用。
如果你正在学习RSpec——试着尽可能少地嘲笑。这将迫使你设计你的类,使它们易于测试。现在你正在用你以前习惯的方式设计它,这使得课程很难测试,这迫使你使用模拟(因为你只是在学习——很容易找不到你什么都不测试的地方(