RSpec: how to test if a method was called?
it "should call 'bar' with appropriate arguments" do
expect(subject).to receive(:bar).with("an argument I want")
subject.foo
end
test that method was called inside another method with rspec
You cannot access tracker
because it is a local variable.
You could stub your set_tracker
method instead and return an instance double:
describe '#track_event' do
let(:tracker_double) { instance_double(Tracker) }
it 'should call event method' do
allow(foo).to receive(:set_tracker).and_return(tracker_double)
expect(tracker_double).to receive(:event)
foo.track_event
end
end
foo
is your test subject.
Rails Rspec - How to test if Service has been called in another Service
Short anwser
describe 'call' do
let(:result) { CheckService.call(params) }
let(:params) { { user_id: "100" } }
## let(:check_user) { instance_double(CheckUser) } delete this
before do
allow(CheckUser).to receive(:call).and_return(true)
end
it do
result
expect(CheckUser).to have_received(:call)
end
end
Alternative
I think a better way to test this is to use DI (Dependency Injection), so you pass CheckUser as a dependency to CheckService. I prefer to write the whole test inside the it
block too!
class CheckService
def initialize(params, check_handler:)
@params = params
@check_handler = check_handler
end
def self.call(params, check_handler: CheckUser)
new(params, check_handler: check_handler).call
end
def call
@check_handler.call(@params[:user_id])
end
end
describe 'call' do
it 'check user with params' do
check_user = class_double(CheckUser)
allow(check_user).to receive(:call).and_return(true)
params = { user_id: "100" }
CheckService.call(params, check_handler: check_user)
expect(check_user).to have_received(:call)
end
end
A blog post to read more about -> https://blog.testdouble.com/posts/2018-05-17-do-we-need-dependency-injection-in-ruby/
How do I test if a method is called on particular objects pulled from the DB in Rails with RSpec?
I realised that I'm really trying to test two aspects of the perform_dangerous_action
method. The first is the scoping of the database fetch, and the second is that it calls the correct method on the User objects that come up.
For testing the scoping of the DB fetch, I should really just make a scope in the User
class:
scope :not_fred, -> { where.not(name: "Fred") }
which can be easily tested with a separate test.
Then the perform_dangerous_action
method becomes
def perform_dangerous_action
User.not_fred.each(&:dangerous_action)
end
and the test to check it calls the right method for not_fred
users is
it "does the dangerous thing" do
user_double = instance_double(User)
expect(user_double).to receive(:dangerous_action)
allow(User).to receive(:not_fred).and_return([user_double])
UserDanger.perform_dangerous_action
end
RSpec - Check if method was called further down(up?) the call stack
RSpec allows you to use the any_instance_of
set of matchers for setting this up.
This can be useful if you need to do this particular type of test and can't manually specify the instances via DI.
expect_any_instance_of(Widget).to receive(:name).and_return("Wobble")
See here
Using Rspec, how can I test a method which calls a method from another class in ruby
You have to call the method correctly. Transaction.new
takes an amount, presumably a number, and some sort of Account object which has balance_after
defined. You've given it two Symbols.
describe Transaction do
let(:account) { Account.new }
let(:amount) { 1.23 }
let(:transaction) { Transaction.new(amount, account) }
let(:timestamp) { Time.now.strftime('%d/%m/%Y') }
Then check that it returns what you expect. balance
does not return true or false, it returns a balance. Specifically, it's just a pass through to account.balance_after(transaction)
, so test that.
describe '#balance' do
it 'checks balance' do
expect(transaction.balance).to eq account.balance_after(transaction)
end
end
This might seem circular, but this is just an integration test. account.balance_after
would be unit tested as part of Account's tests. There's no need to repeat those tests here.
How to check that a method has called another method with RSpec
Remember that expect
and allow
both stub the method call - they prevent it from actually running. If you want to check that one method was called, and also make sure that method calls another method, you need to use .and_call_original
.
# Some setup
folder = "some fake folder" # not sure the data type
report = Reporting::GenerateReports.call
allow(Reporting::GenerateReports).to receive(:call).and_return(stub_report)
# Expectations
expect(Uploader).to receive(:execute).with(some_folder).and_call_original
expect(Uploader).to receive(:upload_file).with(report, folder)
That allow(Reporting::GenerateReports)
line is needed because the report_record
variable is defined inside your execute
method (cannot pass in a custom value from the tests via dependency injection). To ensure that the correct argument is passed to upload_file
, it therefore needs to be stubbed out.
Related Topics
How to Check If a Class Is Defined
How to See the Dependency Tree Just from Gemfile
Which Algorithm Does Ruby's Sort Method Use
What Does the Fail Keyword Do in Ruby
How to Write Columns Header to a CSV File with Ruby
Error Installing Debugger: Failed to Build Gem Native Extension with Ruby-1.9.3-P362
Match String That Doesn't Contain a Specific Word
How to Break from Nested Loops in Ruby
Git Deployment + Configuration Files + Heroku
Retrieving a Braintree Customer's Subscriptions
How to Handle Errors with Httparty
How to Get the Target of a Symlink
What's the Best Way to Search for a String in a File
How to Check If a Variable Is a Number or a String
How to Access (Devise) Current_User in a Rspec Feature Test