I created a Service Object called Transaction which processes an order made, sets up the payments and then sets up a model association.
The class is called Transaction with two methods, initialize
and pay
. I am testing it in spec/services/
(it is in app/services
).
The initialize
method takes in an account
and some parameters passed in by the user to process the order.
I am trying to test pay
with rspec. How do I actually do such a test? This function has a lot going on. For example, it creates new models, and then sets up some associations between them.
So far, I created a double account
as follows:
@account = double("account", :confirmed => true, :confirmed? => true)
However, there are many functions (and associations) used in the Transaction pay method. So for example when these associations are called (once I call Transaction.pay
in the test), it returns an error:
ActiveRecord::AssociationTypeMismatch:
Business(#70250016824700) expected, got RSpec::Mocks:.
The business
model is a double just like account
, and added as an attribute to @account
. How can I test my Transaction.pay when it creates new models and associations in there?
Do I need to mock all of them as shown above? Or is there a better way to do it?
I am using FactoryGirl, but I am unable to use it as my account
model uses Devise. Devise test helpers cannot be used outside of controllers, and since I'm testing in services, it won't work.
It's hard to be specific, since you've not provided your Transaction class code, but at a high level, here's what I'd recommend:
account
.Business
), and if you're creating instances of those from the classes, then they're doubles too.Here's a vague example with no real implementation:
require './app/services/transaction'
describe Transaction do
let(:transaction) { Transaction.new account, :foo => 'bar' }
let(:account) { double 'Account', :confirmed? => true }
let(:business) { double 'Business', :save => true }
before :each do
stub_const 'Business', double(:new => business)
end
describe '#pay' do
it "does stuff" do
# ...
transaction.pay
# ...
end
end
end
You'll note I've only required the transaction file - this helps you be aware of what other classes it depends on, because you'll (ideally) stub the constants, or if necessary, require other files. It'll keep this spec's running time much better too.
Also, I only stubbed confirmed?
, not confirmed
on the account double. From a Rails perspective they mean the same thing, but it's better to use one of them consistently, instead of both.
If you have a ton of setup (a lot of constants and test doubles), then I'd take that as a sign that this Transaction class probably needs to be broken up into several more specific classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With