Interesting post, but that much scaffolding around the tests is a bit of a red flag to me.
I personally try to move as much logic as possible into easily testable, independent methods. This leaves things like Rake tasks as very small, "obviously correct" shells around the actual logic.
I highly recommend checking out the talk Boundaries by Gary Bernhardt[0], which explains this idea far better than I can.
I'm new to Ruby / Rails and using RSpec in general, so I really appreciate any resources people pass along. I'll be sure to check out that talk and may refactor my tests accordingly.
What I like to do with rake tests and/or delayed jobs is write the actual business logic in some other file / module: a module in lib/, a DCI style class, whatever. Then the delayed job / rake task just calls that code.
So your rake / Delayed Job interface is one, maybe two lines. And the body of your code lives somewhere easily testable with standard unit tests without having to mock out Rake (and/or forcing your asnyc queue mechanism to be synchronous for testing).
Thank you for the great comment & suggestion, rpwilcox!
As you recommended, I'll be moving the majority of my actual rake task into a DelayedJob which will perform all the work. The rake task will then only be responsible for queueing up the batches of work and nothing else. And yes, at that point, I could just test the DelayedJob itself vs. the actual execution of the rake task, as I'd have a high degree of confidence that if the DelayedJob works on a model as expected, it will work via DelayedJob in batches.
I decided to write about this first to showcase the capability of explicitly testing rake tasks - I started learning Ruby / Rails about 6 months ago and wanted to share this knowledge. My follow-up post will be on turning this into a DelayedJob.
This was a very useful writeup and am looking forward to your followup with DelayedJob...but what would you say to people who think you could've made the re-calculation methods part of the model? I guess you could argue that you still would want to test any batch task as part of the integration though.
The particular re-calculation method I presented in this blog post is (hopefully) only going to be run one time, as it serves to recalculate fields based on a database migration. Those fields are counter caches in my Rails models, meaning that their values get +1 automatically when an Answer is generated for a particular Question (approved or not).
Given the nature of the task at hand, I felt it was better practice to keep the model 'clean' and abstract the computation to the rake task itself. The computation will soon be extracted out to a DelayedJob, further isolating the re-calculation method in a modular fashion.
I personally try to move as much logic as possible into easily testable, independent methods. This leaves things like Rake tasks as very small, "obviously correct" shells around the actual logic.
I highly recommend checking out the talk Boundaries by Gary Bernhardt[0], which explains this idea far better than I can.
[0]: https://www.destroyallsoftware.com/talks/boundaries