如何用Sinon模拟MongoDB Update错误?测试代码无效求助
Let me walk you through what's likely going wrong with your test and how to fix it to properly trigger the error branch in your route handler.
The Core Issue
Your current test tries to stub db.collection, but there's a good chance the db instance you're stubbing in your test isn't the same one your route handler is actually using. When you import db via tc.__get__('db'), you might be getting a reference that doesn't sync with the live instance in your Express route.
Step-by-Step Fixed Test Code
Here's an adjusted version of your test that ensures the stubbed database methods are properly hooked into your business code, plus adds assertions to verify the error branch runs:
var sinon = require('sinon'); var rewire = require('rewire'); var supertest = require('supertest'); // Supertest is better for Express route testing than superagent var tc = rewire('./file'); var app = require('./your-express-app-file'); // Import your main Express app here // Get references to internal modules in your business code var logger = tc.__get__('logger'); describe('POST /test', () => { let originalDb; let loggerErrorSpy; beforeEach(() => { // Save the original DB reference to restore later originalDb = tc.__get__('db'); // Spy on logger.error to verify it gets called loggerErrorSpy = sinon.spy(logger, 'error'); }); afterEach(() => { // Clean up stubs/spies after each test loggerErrorSpy.restore(); tc.__set__('db', originalDb); }); it('should log an error when MongoDB update fails', (done) => { // 1. Create a stub for the update method that yields an error const updateStub = sinon.stub().yields(new Error('MongoDB update failure')); // 2. Create a stub for db.collection that returns our stubbed collection const collectionStub = sinon.stub().returns({ update: updateStub }); // 3. Replace the DB instance in your business code with our stubbed version tc.__set__('db', { collection: collectionStub }); // 4. Send the POST request to your route supertest(app) .post('/test') .send({ /* Your test payload here */ }) .end((err, res) => { // 5. Verify all our expectations are met sinon.assert.calledOnce(collectionStub); sinon.assert.calledWith(collectionStub, 'test'); sinon.assert.calledOnce(updateStub); sinon.assert.calledOnce(loggerErrorSpy); sinon.assert.calledWith(loggerErrorSpy, sinon.match.instanceOf(Error)); done(); }); }); });
Key Fixes & Explanations
- Use Supertest Instead of Superagent: Supertest integrates directly with your Express app, so you don't need to run a separate server for testing—it's more reliable and simpler for route testing.
- Rewrite the DB Instance: Using
rewire.__set__replaces thedbvariable in your business code entirely, ensuring your route handler uses our stubbed version instead of the original from./setting. - Add Assertions for Logger: The spy on
logger.errorproves the error branch was actually triggered, instead of just assuming the request completed. - Clean Up Stubs: The
beforeEach/afterEachblocks ensure no test pollution—stubs are reset between test runs.
Additional Notes
If your business code caches the collection at the module level (like var collection = db.collection('test') at the top of the file), you'll need to re-set that cached collection after stubbing the DB:
// After setting up the stubbed db tc.__set__('collection', tc.__get__('db').collection('test'));
This ensures the cached collection uses your stubbed update method.
内容的提问来源于stack exchange,提问作者msforest

