RSpec empty? method - ruby

Please tell me how to write a test for this method using Rspec
def to_s
display_name.empty? ? legal_name : display_name
end
I am new and just starting RSpec tests
UPD
My try:
describe "display name" do
it "display name empty" do
legal_name.to_s
expect(display_name).to be_empty
end
end
Tried only one part check
I understand that it is incorrect, but I tried many options

legal_name and display_name are methods of an object, so you need to make an object to test. I don't know what class you're testing, so we'll call it SomeClass.
describe SomeClass do
# Now when you reference `object` this block of code will run,
# but only once per test.
# See https://relishapp.com/rspec/rspec-core/docs/helper-methods/let-and-let
let(:object) {
# Or however you create the object.
SomeClass.new
}
end
You're testing the behavior of the to_s method when the object's display_name method is empty or not. So we have at least two "contexts".
When display_name is empty.
When display_name is not empty.
describe SomeClass do
let(:object) {
SomeClass.new
}
# We're testing its to_s method, not display_name.
describe '#to_s' do
# These are the conditions we're going to test.
# They're just stubs for now.
context 'when display_name is empty'
context 'when display_name is not empty'
end
end
Now that the scaffolding is in place, we can set up the objects in each context using a before hook which contains code to run before each test. I don't know how exactly to do that in your code, I'll just take a guess.
describe SomeClass
let(:object) {
SomeClass.new
}
describe '#to_s' do
context 'when display_name is empty' do
# This will run before each test in this context block
# to make object.display_name empty.
before do
object.display_name = ''
object.legal_name = 'something'
end
end
context 'when display_name is not empty' do
# This will run before each test in this context block
# to make object.display_name not empty.
before do
object.display_name = 'something'
object.legal_name = 'something else'
end
end
end
end
Now in each context the object will be set up correctly.
Finally, add the tests. Call to_s and make sure it returns the expected value, either what's in display_name or what's in legal_name.
describe SomeClass
let(:object) {
SomeClass.new
}
describe '#to_s' do
context 'when display_name is empty' do
before do
object.display_name = ''
object.legal_name = 'legal'
end
it 'uses legal_name' do
expect(object.to_s) to eq 'legal'
end
end
context 'when display_name is not empty' do
before do
object.display_name = 'display'
object.legal_name = 'legal'
end
it 'uses display_name' do
expect(object.to_s) to eq 'display'
end
end
end
end
It's a lot of scaffolding, but it makes it very clear what situations are being tested.
As a final note, consider another context...
context 'when display_name is blank' do
before do
object.display_name = ' '
object.legal_name = 'legal'
end
end
What should happen there? Look into blank?.

Related

How am I supposed to validate this custom matcher in RSpec

I have started studying Rspec recently and a got a challenge to solve: Do an object capable of recognize some keys using Regex.
The object needs to pass in a bunch of Rspec tests.
Here are some examples:
describe '#phone?' do
context 'when receive a valid phone' do
[
'+55861107350',
].each do |key|
context "when key is #{key}" do
let(:key) { key }
it { is_expected.to be_a_phone }
end
end
end
context 'when receive an invalid phone' do
[
'55861107350',
'jake#gmail',
'123e4567-e89b-12d3-a456-426655440000'
].each do |key|
context "when key is #{key}" do
it { is_expected.not_to be_a_phone }
end
end
end
What I'm not getting is how am I supposed to validate the be_a_phone matcher, since in the challenge says I can only modify the class file(which is empty and I need to create)
I have been researching about custom matchers and the way you define a custom matcher is by creating the method in another spec file, and supposedly I'm not allow to do that.
Can I make a Rspec::matchers.define :be_a_phone inside a class? or a class file?
My class(it's very raw):
# frozen_string_literal: true
class Key
attr_reader :key, :type
def initialize(key)
#key = key.to_s
#type = ''
self.define_type
end
def set_key(newKey)
#key = newKey
end
def set_type(newType)
#type = newType
end
def define_type
if self.key.scan(/^\+[1-9][0-9]\d{1,14}$/)[0] == self.key
puts "Your key is a valid Phone"
self.set_type("phone")
return "valid"
return self.set_key("invalid")
end
end

What's best practice for mocking new method on different class

I have next scenario:
module Module
class CommandPattern
def initialize(value)
command = []
#var = value['something']
#abc = value['abc']
#command << value
end
def add(value)
#command << value
end
def get_command
#command
end
end
end
module Module
class Implementator
def initialize(value)
#value = value
end
def method_to_test(argument)
var = "command1"
cmd = CommandPattern.new(var)
var2 = "command2"
cmd.add(var2)
var3 = argument
cmd.add(var3)
commands = var + var2 + var3
commands
end
end
end
So, when I'm testing Module::B.method_I_want_to_test, what would be the best practice to mock "var = A.new(some_stuff)"? Beside refactoring and moving this line into separate method, is there some nice way to do this?
Little bit of background on this question - this style (Module::ClassA and Module::ClassB) - I'm using http://naildrivin5.com/gli/ and reason for this approach is that class A is actually implementing Command Pattern.
So issue I was apparently getting was due to wrong way of trying to write specs.
What I did before was (on the way how #spickermann advised):
RSpec.describe Module::Implementator do
describe "#method_to_test" do
let(:command_argument) { "command" }
let(:cmnd) { double(CommandPattern, :new => command_argument, :add => command_argument)}
subject(:method_to_test) do
Implementator.new("value").method_to_test("dejan")
end
before do
allow(CommandPattern).to receive(:new).with(any_args).and_return(cmnd)
allow(CommandPattern).to receive(:add).with(any_args).and_return(cmnd)
end
it 'does something' do
expect{ method_to_test }.not_to raise_error
end
it 'does something else' do
result = method_to_test
expect(result).to eq("command1command2dejan")
end
end
end
Issue was apparently in testing Module::Implementator, didn't realise I can put module around my RSpec.describe block and solve my first issue:
module Module
RSpec.describe Implementator do
describe "#method_to_test" do
let(:command_argument) { "command" }
let(:cmnd) { double(CommandPattern, :new => command_argument, :add => command_argument)}
subject(:method_to_test) do
Implementator.new("value").method_to_test("dejan")
end
before do
allow(CommandPattern).to receive(:new).with(any_args).and_return(cmnd)
allow(CommandPattern).to receive(:add).with(any_args).and_return(cmnd)
end
it 'does something' do
expect{ method_to_test }.not_to raise_error
end
it 'does something else' do
result = method_to_test
expect(result).to eq("command1command2dejan")
end
end
end
end
Another issue I had was global variable keeping YAML structure, which I missed to see and declare in spec_helper.rb
However, thank's to #spickermann's advices, issue is solved.
I would start with something like this:
describe '#method_I_want_to_test' do
let(:something) { # whatever something needs to be }
let(:a) { double(A, # methods you need from a) }
subject(:method_I_want_to_test) do
B.new(something).method_I_want_to_test
end
before do
allow(A).to receive(:new).with(something).and_return(a)
end
it 'does what I expect' do
expect(method_I_want_to_test).to eq(# what do_semething_else returns)
end
end
The interesting part is the before block that stubs the new method on A. It returns always the double defined in the let(:a) line instead of a real instance of A

How to implement this rspec snippets

I would like to know what happened behind this snippet
How Ruby implements this syntax ?
feature "Course" do DO_SOMETHING end
scenario "A Course without name should not be accepted" do
end
Please give me some concrete direction or example
feature "Course" do
let(:school) {School.make!}
context "Logged in" do
before(:each) do
switch_to_subdomain(school)
end
context "In the new course form" do
before(:each) do
click_link("Courses")
click_link("New course")
end
scenario "New course" do
end
scenario "A Course without name should not be accepted" do
end
scenario "A new course should not be created if there is another one with the same name in the same school" do
end
end
end
end
In ruby, you can pass a block as the last parameter to a method, which can then either call it using yield, or treat it as an explicit variable, moving it around etc.
def scenario(name)
puts name
if block_given?
yield
end
end
def feature(name, &block)
puts name
if block_given?
scenario("called from feature", &block)
end
end
scenario("test") do puts "this" end
# => test
# => this
feature("test") do puts "this" end
# => test
# => called from feature
# => this
Also, since parentheses are optional in ruby, you can drop them receiving this syntax:
scenario "test" do
puts "this"
end
# => test
# => this
feature "test" do
puts "this"
end
# => test
# => called from feature
# => this

RSpec lazy subject

When testing class methods, I don't need an instance to be created automatically. Is an implicit subject created automatically, or only when referenced?
describe MyClass do
it 'uses implicit subject' do
subject.my_method.should be_true
end
it 'does not create a subject' do
MyClass.works?.should be_true
# subject should not have been created
end
end
subject appears to be a method which creates the object necessary and returns it. So it would only create a subject object when called.
It's easy enough to test yourself though...
class MyClass
cattr_accessor :initialized
def initialize
MyClass.initialized = true
end
def my_method
true
end
def self.works?
true
end
end
describe MyClass do
it 'uses implicit subject' do
MyClass.initialized = false
subject.my_method.should be_true
MyClass.initialized.should == true
end
it 'does not create a subject' do
MyClass.initialized = false
MyClass.works?.should be_true
MyClass.initialized.should == false
end
end
Those specs pass, proving that it's lazy.

RSpec - spec fails when trying to call method on initialized attribute

Here is the code for my specs and class:
describe Game do
before(:each) do
#game = Factory.build(:game)
end
describe '#no_books?' do
it 'should return true if books attribute is empty' do
#game.stub(:books).and_return([])
#game.no_books?.should be_true
end
it 'should return false if books attribute is present' do
#game.no_books?.should be_false
end
end
end
class Game
attr_reader :books
def initialize
#books = parse_books
end
def no_books?
#books.empty?
end
protected
def parse_books
# return books
end
end
I then get a friendly spec failure message:
Game#no_books? should return true if books attribute is empty
Failure/Error: #game.no_books?.should be_true
expected false to be true
It's as if that method is getting called before the attribute books get initialized with a value. Can someone explain to me what's going here?
Your no_books? implementation is using the instance variable directly in its check, bypassing your stub. If you change no_books? to return books.empty?, it will call the stub instead.
If you really, really want to keep using the instance variable, you can set it in #game via instance_variable_set like this:
#game.instance_variable_set("#books", [])

Resources