its method: which is like it but applies the subsequent test to the given attribute rather than the subject of the test. In other words,
its(:remember_token) { should_not be_blank } == it { @user.remember_token.should_not be_blank }
before(:each): The blobk passed to before(:each) will be run before each example. The before block and the example are executed in the same object, so they have access to the same instance variables. Adding all of those @ symbols can be tedious and error prome, so RSpec offers an alternative approach.
describe "#start" do
before(:each) do
@output = double('output').as_null_object
@game = Game.new(@output)
end
end
Let method: When the code in a before block is only creating instance variables and assigning them values, which is most of the time, we can use RSpec's let() method instead. let() takes a symbol representing a method name and a block, which represents the implementation of that method.
let(:output) { double('output').as_null_object }
let(:game) { Game.new(output) }
Memoized: It means that the first time the method is invoked, the return value is cached and that same value is returned every subsequent time the method is invoked within the same scope. #may edit, but I believe this means that you can cache instance variables to call them later without the @ sign.
Subject Code: The code whose behavior we are specifying with RSpec.
Expectation: An expression of how the subject code is expected to behave.
Code Example: An executable example of how the subject code can be used and its expected behavior (expressed with expectations) in a given context. In BD, we write the code examples before the subject code they document. Using example instead of test reminds us that writing them is a design and documentation practive, even though once they are written and the code is developed against them, they become regression tests.
Example Group: A group of code examples.
spec aka spec file: A file that contains one or more example groups.
Describe Method: The describe() method takes an arbitrary number of arguments and an optional block and returns a subclass of RSpec::Core::ExampleGroup. We typically use only one or two arguments, which represent the facet of behavior that we want to describe. They might describe an object, perhaps in a predefined state or perhaps a subset of the behavior we can expect from that object.
You: describe a new account
Somebody else: It should have a balance of zero
RSpec:
describe "A new account" do
it "should have a balance of 0" do
account = Account.new
account.balance.should == Money.new(0, :USD)
end
end
Context Method: The context() method is an alias for describe(), so they can be used interchangeably. We tend to use describe() for things and context() for context.
describe User do
context "with no roles assigned" do
it "is not allowed to view protected content" do
The output would be the same as when we used describe() on the second line, but context() can make it easier to scan a spec file and understand what relates to what.
It Method: Similar to describe, the it() method takes a single string, an optional hash, and an optional block. The string should be a sentence when prefixed with "it," represents the detail that will be expressed in the code within the block. Here is an example specifying a stack:
describe Stack do
before(:each) do
@stack = Stack.new
@stack.push :item
end
describe "#peek" do
it "should return the top element" do
@stack.peak.should == :item
end
it "should not remove the top element" do
@stack.peek
@stack.size.should == 1
end
end
describe "#pop" do
it "should return the top element" do
@stack.pop.should == :item
end
it "should remove the top element" do
@stack.pop
@stack.size.should == 0
end
end
end
Pending Examples: RSpec supports pending examples by using the it() method without a do-end block. This allows us to organize our thoughts and examples before running tests ont them to be failing or passing. You can also write pending in the example so it is not executed by putting pending in the example as shown in the example below. Here is an example of both:
pending: use to basically comment out example without getting rid of it
it "should be white" do
pending "should include white"
Newspaper.new.colors.should include('white')
end
no block: just pending to
it "should be read all over"
pending wrapper: This is a way to have a pending wrapper that can still run to pass and then can be taken away once it is passing.
describe "an empty array" do
it "should be empty" do
pending("bug report 18976") do
[].should be_empty
end
end
end
Hooks:
before(:each) Method: This is used in for all examples in the example group. This is great because you can instantiate locally in an example group and it will remain self contained to not move over into other example groups.
context "when full" do
before(:each) do
@stack = Stack.new
(1..10).each { |n| @stack.push n }
end
end
before(:all) Method: This is one to be careful of because it will instantiate the object across the entire spec which can have adverse effects if there are many things and methods being run in the examples.
after(:each) Method: This is rarely necessary because each example runs in its own scrope, and the instance variables consequently go out of scope after each example. If you're dealing with a system that maintains some global state that you want to modify just for an example, a common idiom for this is to set aside the global state in an instance variable in before(:each) and then restore it in after(:each):
before(:each) do
@original_global_value = $some_global_value
$some_global_value = temporary_value
end
after(:each) do
$some_global_value = @original_global_value
end
after(:all) Method: this is even more rare than the after(:each). The time when this is justified are examples that include closing down browsers, closing database connections, closing sockets, and so on. Basically, any resources that we want to ensure get shut down but not after every example.
around(:each) Method: RSpec provides an around() hook to support APIs that require a block. The most common use case for this is database transactions:
around do |example|
DB.transaction { example.run }
end
Helper Methods:
defining methods within RSpec as a helper to DRY out code
describe Thing do
def create_thing(options)
thing = Thing.new
thing.set_status(options[:status])
thing
end
end
Creating helper methods within a Module to share across example groups
module UserExampleHelpers
def create_valid_user
User.new(email: 'email@example.com', password: 'shhhhh')
end
def create_invalid_user
User.new(password: 'shhhhh')
end
end
Module used inside the RSpec code
describe User do
include UserExampleHelpers
it "does something when it is valid" do
user = create_valid_user
#do_stuff
end
it "does something when it is not valid" do
user = create_invalid_user
#do_stuff
end
end
Shared Examples:
When we expect instances of more than one class to behave in the same way, we can use a shared example group to describe it once and then include that example group in other example groups. We declare a shared example group with the shared_examples_for() method:
shared_examples_for "any pizza" do
it "tastes really good" do
@pizza.should taste_really_good
end
it "is available by the slice" do
@pizza.should be_available_by_the_slice
end
end
In order to call it you can use the it_behaves_like() method:
it_behaves_like "any pizza"
Nested Example Group:
Nesting example groups is a great way to organize examples within one spec. Here's a simple example:
describe "outer" do
describe "inner" do
end
end
If we want to express a given in the outer group, an event (or when) in the inner group, and the expected outcome in the examples themselves. We can do something like this:
describe Stack do
before(:each) do
@stack = Stack.new(capacity: 10)
end
describe "when full" do
(1..10).each { |n| @stack.push n }
end
describe "when it receives push" do
it "should raise an error" do
lambda { @stack.push 11 }.should raise_error(StackOverflowError)
end
end
end
describe "when almost full (one less than capacity)"
before(:each) do
(1..9).each { |n| @stack.push n }
end
describe " when it receives push" do
it "should be full" do
@stack.push 10
@stack.should be_full
end
end
end
RSpec::Expectations
should matcher: result.should equal(5). This is an example of an expectation and not an assertion for what RSpec is testing. Ruby begins with the equal(5). The matcher then becomes the argument to result.should.
should_not matcher: result.should_not equal (10). This example works the same way and is the opposite of the should matcher. If matches?(self) returns false, then the expectation is met.
include(item) matcher: prime_numbers.should_not include(8)
respond_to(message) matcher: lists.should respond_to(:length)
raise_error(type) matcher: lambda { Object.new.explode! }.should raise_error(NameError)
Object Equivalence and Object Identity:
a.should == b
This is the most common form of equality because we are generally concerned with value equality, not object identity
user = User.create!(name: "John")
User.find_by_name("John").should equal(user)
This puts a much greater restriction because now the User.create! has to ALWAYS be "John" in order to pass which makes it a much more brittle test.
*Do NOT use != because it is not supported by RSpec
Floating Point Calculations:
result.should be_close(5.25, 0.005)
The be_close matcher has the ability to take in an argument and set a range of how far it can be away from the number in order to make sure that floating point numbers do not fail when they rightfully should pass.
Changes: by(), to(), and from() calls can be bound together in order to show changes.
expect {
User.create!(:role => "admin")
}.to change{ User.admins.count }.by(1)
Expecting Errors: Want to use the raise_error matcher in order to provide error classes and messages that provide context to what went wrong. The raise_error matcher will accept zero, one, or two arguments.
account = Account.new 50, :dollars
expect {
account.withdraw 75, :dollars
}.to raise_error(
InsufficientFundsError,
/attempted to withdraw 75 dollars from an account with 50 dollars/
)
Expecting a Throw: throw() and catch() allow us to stop execution within a given scope based on some condition. The main difference is that we use throw/catch to express EXPECTED circumstances as opposed to exceptional circumstances. The throw_symbol() matcher will accept zero, one, or two arguments.
course = Course.new(:seats => 20)
20.times { course.register Student.new }
lambda {
course.register Student.new
} should throw_symbol(:course_full, 20)
Predicate Matchers: A Ruby predicate method is one whose name ends with "?" and returns a Boolean response.
array.empty?.should == true
OR
array.should be_empty
False and True Matchers: be_true and be_false matchers
true.should be_true
0.should be_true
false.should be_false
nil.should be_false
Have Key: Looks for specific keys in a hash and if they are present.
request_parameters.has_keys?(:id).should == true
OR
request_parameters.should have_key(:id)
Owned Collections: How to specify how to send out 9 players on the field in fantasy football.
field.players.select { |p| p.team == home_team }.length.should == 9
OR
home_team.should have(9).players_on(field)
Unowned Collections: This is for times when the object you're describing is itself a collection. RSpec lets us use have to express this as well:
collection.should have(37).items
Strings: Strings are collections too. Because strings respond to length and size, you can also use have to expect a string of a specific length.
"this string".should have(11).characters
Precision in Collection Expectations: Collection expectations can be expressed with exactly that number, at least that number or at most that number.
days.should have_exactly(24).hours
dozen_bagels.should have_at_least(12).bagels
internet.should have_at_most(2037).killer_social_networking_apps
How Have Works
The have method can handle various scenarios. The object returned by have is an instance of RSpec::Matchers:Have, which gets initialized with the expected number of elements in a collection.
result.should have(3).things
is the equivalent of this expression:
result.should(Have.new(3).things)
Next, the Ruby interpreter sends things to the Have object. Then method_missing is invoked because Have doesn't respond to things. Have overrides method_missing to store the message name for later use and then returns self.
Operator Expressions:
it "should generate a 1 10% of the time (plus/minus 2%)" do
result.occurrences_of(1).should be_greater_than_or_equal_to(980)
result.occurrences_of(1).should be_less_than_or_equal_to(1020)
end
The better way:
result.should == 3
result.should =~ /some regexp/
result.should be < 7
result.should be <= 7
result.should be >= 7
result.should be > 7
Generated Descriptions:
describe "A new chess board" do
before(:each) do
@board = Chess::Board.new
end
it "should have 32 pieces" do
@board.should have (32).pieces
end
end
Subjectivity: The subject of an example if the object being described. The subject is an instance of RSpecUser. RSpec offers an alternative to setting up instance variables in before blocks like this, in the form of the subject() method.
Explicit Subject:
describe Person do
subject { Person.new(:birthdate => 19.years.ago }
end
Delegation to Subject: Once a subject is declared, that example should delegate should() and should_not() to that subject, allowing the code to clean up.
describe Person do
subject { Person.new(:birthdate => 19.years.ago }
it { should be_eligible_to_vote }
end
Implicit Subject: We want to create a subject by calling a new on the RSpecUser class without any arguments. In cases like this, we can leave out the explicit subject declaration, and RSpec will create an implicit subject for us:
describe RSpecUser do
it { should be_happy }
end
That is it for now. LONGEST POST EVER, sorry it is more notes for me than anything. Hope this helps.
should_not matcher: result.should_not equal (10). This example works the same way and is the opposite of the should matcher. If matches?(self) returns false, then the expectation is met.
include(item) matcher: prime_numbers.should_not include(8)
respond_to(message) matcher: lists.should respond_to(:length)
raise_error(type) matcher: lambda { Object.new.explode! }.should raise_error(NameError)
Object Equivalence and Object Identity:
a.should == b
This is the most common form of equality because we are generally concerned with value equality, not object identity
user = User.create!(name: "John")
User.find_by_name("John").should equal(user)
This puts a much greater restriction because now the User.create! has to ALWAYS be "John" in order to pass which makes it a much more brittle test.
*Do NOT use != because it is not supported by RSpec
Floating Point Calculations:
result.should be_close(5.25, 0.005)
The be_close matcher has the ability to take in an argument and set a range of how far it can be away from the number in order to make sure that floating point numbers do not fail when they rightfully should pass.
Changes: by(), to(), and from() calls can be bound together in order to show changes.
expect {
User.create!(:role => "admin")
}.to change{ User.admins.count }.by(1)
Expecting Errors: Want to use the raise_error matcher in order to provide error classes and messages that provide context to what went wrong. The raise_error matcher will accept zero, one, or two arguments.
account = Account.new 50, :dollars
expect {
account.withdraw 75, :dollars
}.to raise_error(
InsufficientFundsError,
/attempted to withdraw 75 dollars from an account with 50 dollars/
)
Expecting a Throw: throw() and catch() allow us to stop execution within a given scope based on some condition. The main difference is that we use throw/catch to express EXPECTED circumstances as opposed to exceptional circumstances. The throw_symbol() matcher will accept zero, one, or two arguments.
course = Course.new(:seats => 20)
20.times { course.register Student.new }
lambda {
course.register Student.new
} should throw_symbol(:course_full, 20)
Predicate Matchers: A Ruby predicate method is one whose name ends with "?" and returns a Boolean response.
array.empty?.should == true
OR
array.should be_empty
False and True Matchers: be_true and be_false matchers
true.should be_true
0.should be_true
false.should be_false
nil.should be_false
Have Key: Looks for specific keys in a hash and if they are present.
request_parameters.has_keys?(:id).should == true
OR
request_parameters.should have_key(:id)
Owned Collections: How to specify how to send out 9 players on the field in fantasy football.
field.players.select { |p| p.team == home_team }.length.should == 9
OR
home_team.should have(9).players_on(field)
Unowned Collections: This is for times when the object you're describing is itself a collection. RSpec lets us use have to express this as well:
collection.should have(37).items
Strings: Strings are collections too. Because strings respond to length and size, you can also use have to expect a string of a specific length.
"this string".should have(11).characters
Precision in Collection Expectations: Collection expectations can be expressed with exactly that number, at least that number or at most that number.
days.should have_exactly(24).hours
dozen_bagels.should have_at_least(12).bagels
internet.should have_at_most(2037).killer_social_networking_apps
How Have Works
The have method can handle various scenarios. The object returned by have is an instance of RSpec::Matchers:Have, which gets initialized with the expected number of elements in a collection.
result.should have(3).things
is the equivalent of this expression:
result.should(Have.new(3).things)
Next, the Ruby interpreter sends things to the Have object. Then method_missing is invoked because Have doesn't respond to things. Have overrides method_missing to store the message name for later use and then returns self.
Operator Expressions:
it "should generate a 1 10% of the time (plus/minus 2%)" do
result.occurrences_of(1).should be_greater_than_or_equal_to(980)
result.occurrences_of(1).should be_less_than_or_equal_to(1020)
end
The better way:
result.should == 3
result.should =~ /some regexp/
result.should be < 7
result.should be <= 7
result.should be >= 7
result.should be > 7
Generated Descriptions:
describe "A new chess board" do
before(:each) do
@board = Chess::Board.new
end
it "should have 32 pieces" do
@board.should have (32).pieces
end
end
Subjectivity: The subject of an example if the object being described. The subject is an instance of RSpecUser. RSpec offers an alternative to setting up instance variables in before blocks like this, in the form of the subject() method.
Explicit Subject:
describe Person do
subject { Person.new(:birthdate => 19.years.ago }
end
Delegation to Subject: Once a subject is declared, that example should delegate should() and should_not() to that subject, allowing the code to clean up.
describe Person do
subject { Person.new(:birthdate => 19.years.ago }
it { should be_eligible_to_vote }
end
Implicit Subject: We want to create a subject by calling a new on the RSpecUser class without any arguments. In cases like this, we can leave out the explicit subject declaration, and RSpec will create an implicit subject for us:
describe RSpecUser do
it { should be_happy }
end
That is it for now. LONGEST POST EVER, sorry it is more notes for me than anything. Hope this helps.
No comments:
Post a Comment