Jwan622
Jwan622

Reputation: 11659

First time unit testing with rspec in ruby

I am just trying to understand the basics behind unit testing. I wrote a Player class in a file called Player.rb. Here is the code:

Class Player

  attr_reader :health
  attr_accessor :name

 def initialize(name, health=100)
    @name = name.capitalize
    @health = health
 end

 def blam
    @health -= 10
    puts "#{@name} just got blammed yo."
 end

 def w00t
    @health += 15
    puts "#{@name} just got w00ted."
 end

 def score
    @health + @name.length
 end

 def name=(new_name)
    @name = new_name.capitalize
 end

 def to_s
    puts "I'm #{@name} with a health of #{@health} and a score of #{score}"
 end
end

Here is my spec file:

require_relative 'Player'

describe Player do
    it "has a capitalized name" do
        player = Player.new("larry", 150)

        player.name.should == "Larry"
    end
end

Does that seem about right? My question is in regards to the syntax of the spec file. I understand why I need to require the Player class. But what is the describe and it sections of the code doing? Why do I need the it section? All it seems to be doing is defining a string right?

Finally, when I run rspec player_spec.rb from Terminal, I get this warning:

Deprecation Warnings:

Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` instead. Called from /Users/Jwan/studio_game/player_spec.rb:7:in `block (2 levels) in <top (required)>'.

What does the above warning mean? Do I have to replace should with enable syntax? How do I enable the :should syntax? Why is :should written as a symbol?

Upvotes: 1

Views: 1213

Answers (2)

max
max

Reputation: 102250

it sets up an actual example. An example can be thought of as an actual test which contains one or more expectations (best practice says one expectation per example). The expect method and matchers only exist in the it block. Variables set up with let and subject are unique for each example.

scenario is an alias for it used in feature (acceptance) specs.

describe, context and feature are used to group examples together. This provides both readability and encapsulation for let and subject variables.

Passing a class to describe also sets up an implicit subject:

RSpec.describe Array do
  describe "when first created" do
    it { is_expected.to be_empty }
  end
end

RSpec has relativly recently undergone a large shift towards eliminating "monkey patching" core ruby classes which depreciated the should syntax.

While it is recommended to use expect for new projects, you can allow should and other monkey patching methods.

Upvotes: 2

Jordan Running
Jordan Running

Reputation: 106087

Yes, that seems about right. One thing you might find useful is to use subject, which lets you define a "subject" to use in multiple tests:

describe Player do
  subject { Player.new("larry", 150) }

  it "has a capitalized name" do
    expect(subject.name).to eq "Larry"
  end
end

This way you don't have to define player over and over again in every test—subject will automatically initialize it for you each time.

describe and it are primarily for organization. A large project will ultimately have thousands of tests, and a change in one class might cause a test to fail for a completely different part of application. Keeping tests organized makes it much easier to find and fix errors as they occur.

As for your warning, it looks like you're using an old guide or tutorial that tells you to use "should" syntax, but in RSpec 3 this syntax is deprecated and "expect" syntax is required instead. You can see how I changed your code above to use "expect" syntax. Here's a good blog post on the new syntax (and why the old syntax is deprecated).

Upvotes: 6

Related Questions