RSpec控制器测试失败:Buy交易状态未更新为done求助
buy.trading_status Remains "pending" Instead of "done" Let's break down your issue and walk through actionable fixes to get your test passing:
Problem Recap
You're trying to verify that the #new action in your BuysController properly executes database changes, but your test is failing with:
- A "no save" message (confirming
buy.savefailed) - An expectation mismatch: expected
buy.trading_statusto be "done", got "pending"
You’ve already tried running rake db:test:prepare and RAILS_ENV=test rake db:migrate without resolving the issue.
Key Issues in Your Test Code
Let’s unpack why your test isn’t behaving as expected:
You’re not actually testing the controller’s
#newaction
Your test manually creates aBuyinstance and callsmarket_checkeroutside the controller’s context. This doesn’t replicate what happens when a user hits the#newroute—you need to trigger the controller action directly to test its logic.Hardcoded IDs are causing save failures
You’re manually settingid:1for bothSellandBuy. If your test database has leftover data (or the primary key sequence isn’t reset), this will trigger a duplicate primary key error, which is whybuy.saveis failing (hence the "no save" log).Uncertainty whether
market_checkerpersists changes
If your helper only updates thetrading_statusattribute without callingsaveon thebuyinstance, the change won’t be written to the database.Potential confusion between
#newand#createactions
In Rails convention,#newis a GET action that renders a creation form, while#createis the POST action that processes and saves the record. Double-check which action contains your database modification logic.
Step-by-Step Fixes
1. Diagnose the Exact Cause of the Save Failure
First, add error logging to see why buy.save is failing. Modify your test’s else block:
else p "no save" p buy.errors.full_messages # This will show validation/database errors end
Running the test again will reveal if it’s a validation issue, duplicate ID, missing required fields, etc.
2. Rewrite the Test to Target the Controller Action
Instead of manually creating a Buy instance, trigger the controller action and check the actual database record. Here’s a revised test (assuming your logic lives in #create—adjust if it’s truly in #new):
require 'rails_helper' include BuysHelper RSpec.describe BuysController, type: :controller do describe "POST #create" do it "sets buy's trading_status to 'done' after creation" do # Create dependencies without hardcoding IDs user = User.create!(name: "hhhvv", email: "gggjggg@gmail.com") currency = Currency.create!(name: "hello", user_id: user.id) Sell.create!(user_id: user.id, currency_id: currency.id, amount: 100, price: 100, trading_status: "pending") # Trigger the controller's create action with valid params post :create, params: { buy: { user_id: user.id, currency_id: currency.id, amount: 100, price: 100, trading_status: "pending" } } # Fetch the created buy from the database (not the in-memory instance) created_buy = Buy.last expect(created_buy.trading_status).to eq("done") end end end
3. Ensure market_checker Persists Changes
Verify your helper method actually saves the trading_status update. For example:
# In buys_helper.rb def market_checker(buy) buy.trading_status = "done" buy.save! # Use save! to raise an error if save fails (easier debugging) end
If you’re not passing the buy instance to the helper, or modifying a copy instead of the original, the change won’t stick.
4. Reset Your Test Database
Leftover data can cause unexpected conflicts. Reset the test database to a clean state:
RAILS_ENV=test rake db:reset
This drops, recreates, migrates, and seeds (if applicable) the test database, ensuring no residual data interferes with your tests.
Final Tips
- Avoid hardcoding IDs in tests—let Rails handle primary key generation to prevent conflicts.
- Use
create!instead ofcreatein tests (it raises an error if creation fails, speeding up debugging). - Confirm you’re testing the correct controller action (don’t mix up
#newand#create).
内容的提问来源于stack exchange,提问作者Ryu Nishida

