Generated test environment config prevents classes from being partially doubled in tests
greveritt opened this issue · comments
Checklist
- Upgrade Jets: Are you using the latest version of Jets? This allows Jets to fix issues fast. There's a
jets upgrade
command that makes this a simple task. There's also an Upgrading Guide: http://rubyonjets.com/docs/upgrading/ - Reproducibility: Are you reporting a bug others will be able to reproduce and not asking a question. If you're unsure or want to ask a question, do so on https://community.boltops.com
- Code sample: Have you put together a code sample to reproduce the issue and make it available? Code samples help speed up fixes dramatically. If it's an easily reproducible issue, then code samples are not needed. If you're unsure, please include a code sample.
My Environment
Software | Version |
---|---|
macOS | 14.4.1 (23E224) |
Jets | 5.0.12 |
Ruby | 3.2.3 |
Expected Behaviour
The following RSpec code prevents the actual implementation of ClassName#method_name
from being run in the test example.
allow(ClassName).to receive(:method_name).and_raise 'Whoopsy daisy!'
Current Behavior
The original implementation of ClassName#method_name
is run.
Step-by-step reproduction instructions
I created an example application that demonstrates the issue. I may have experienced this bug more consistently in controller tests, so the example app partially mocks a non-controller class inside of a controller spec.
- Clone the git repository linked to below.
- Make sure you're on branch
main
. - Run
bundle exec rspec spec/controllers/demo_controller_spec.rb
on the command line. NOTE: You can write a similar spec in your own test application by creating a class outside of the Jets class hierarchy, mocking a class method on that class, and writing an expectation for the mocked behavior.
You will see test output similar to this:
Failing test output
DemoController
GET #index
when the utility class is not stubbed
executes the original method
when the utility class is partially stubbed to raise an error
rescues the error and returns a 500 status (FAILED - 1)
Failures:
1) DemoController GET #index when the utility class is partially stubbed to raise an error rescues the error and returns a 500 status
Failure/Error: expect { get '/demo' }.to raise_error 'Whoopsy daisy!'
expected Exception with "Whoopsy daisy!" but nothing was raised
# ./spec/controllers/demo_controller_spec.rb:18:in `block (4 levels) in <top (required)>'
Finished in 0.03077 seconds (files took 0.93326 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/controllers/demo_controller_spec.rb:17 # DemoController GET #index when the utility class is partially stubbed to raise an error rescues the error and returns a 500 status
How to write your own test application
- Create a new API app like so:
jets new class-caching-error-demo --mode api
- Write a new non-controller class outside of the Jets hierarchy in a file such as
app/utilities/demo_utility.rb
. This class will be referred to as "the utility class" from here on out. - Call a method of the utility class in a controller action.
- Partially mock a class method of the utility class in the controller spec.
- Write a test example that expects the mocked behavior and place it in the same scope as the partial mock.
Code Sample
Git repository of test application
Solution Suggestion
Change the template for the test application environment so that configuration option cache_classes
is set to true
, not false
. Setting this option to false
makes it so that the partially mocked class is reloaded without the mock when it's used in the application code under test.
The Jets default is also the opposite of the Rails default. In Rails, cache_classes
is set to true
in testing environments unless Spring is installed. Generated Jets apps do not come with Spring. Please refer to the documentation of config.cache_classes
in Rails 7.0. I have chosen to refer to the Rails 7.0 manual because Jets 5.0.12 includes libraries from Rails 7.0.8.1.
The test app's Git repo has a branch called fix-test-config
, which has cache_classes
set to true
, contrary to the Jets default. The tests in demo_controller_spec.rb
pass on that branch:
Output of tests succeeding with fixed test environment configuration
DemoController
GET #index
when the utility class is not stubbed
executes the original method
when the utility class is partially stubbed to raise an error
rescues the error and returns a 500 status
Finished in 0.01534 seconds (files took 0.87718 seconds to load)
2 examples, 0 failures
@tongueroo Was there a specific reason why cache_classes
was set to false
by default? I haven't experienced any ill effects from enabling it in my project. I've only experienced the benefits of partial class doubles working again. Please let me know if there is anything I can do to improve the pull request that I created: #722.
This was resolved by #722. Thanks, @tongueroo!