Javascript 在测试中似乎根本并没有调用Sinon存根,即使它在以前的测试中工作

Javascript 在测试中似乎根本并没有调用Sinon存根,即使它在以前的测试中工作,javascript,unit-testing,express,mocha.js,sinon,Javascript,Unit Testing,Express,Mocha.js,Sinon,我正试图用sinon测试express路由器的功能。下面是我的测试,第一个测试通过得很好,没有问题。然而,第二个没有通过。我不明白为什么 如果我向路由发送http请求,它将按预期工作 渔获量引起了一些问题。下面是代码,我能够削减到它和错误 books.js import express from 'express'; import models from '../db/models'; const router = express.Router(); var indexPost = async

我正试图用sinon测试express路由器的功能。下面是我的测试,第一个测试通过得很好,没有问题。然而,第二个没有通过。我不明白为什么

如果我向路由发送http请求,它将按预期工作

渔获量引起了一些问题。下面是代码,我能够削减到它和错误

books.js

import express from 'express';
import models from '../db/models';
const router = express.Router();

var indexPost = async (req, res, next) => {
  try {
    let savedBook = await models.Book.create({
      title: req.body.title || null,
      isbn: req.body.isbn || null,
      author: req.body.author || null
    });
    res.status(201).json({ book: savedBook.id });
  } catch (err) {
    res.status(400).send('');
  }
};
router.post('/', indexPost);

export default router;
export { indexPost };
import { indexPost } from '../../../src/routes/books';
import models from '../../../src/db/models';
import sinon from 'sinon';
import { expect } from 'chai';
import sinonTestFactory from 'sinon-test';

const sinonTest = sinonTestFactory(sinon);

describe('Books router', () => {
  describe('indexPost', () => {
    it('should save the book to the database', sinonTest(async function () {
      let req = {
        body: {
          title: 'Book Title',
          isbn: '123asera23',
          author: 123
        }
      };

      let res = {
        status: status => {},
        json: json => {}
      };

      this.stub(res, 'status').returns(res);
      this.stub(res, 'json').returns(res);

      indexPost(req, res);

      let book = await models.Key.findById(1);

      expect(book.title).to.equal('Book Title');
      expect(book.isbn).to.equal('123asera23');
      expect(book.author).to.equal(123);

      sinon.assert.calledWith(res.status, 201);
      sinon.assert.calledWith(res.json, { book: 1 });
    }));

    it('should throw an error if data is not all there', sinonTest(async function () {
      let req = {
        body: {
          title: 'Book Title',
          author: 123
        }
      };

      let res = {
        status: status => {},
        send: send => {}
      };

      this.stub(res, 'status').returns(res);
      this.stub(res, 'send').returns(res);

      indexPost(req, res);

      sinon.assert.calledWith(res.status, 400);
      sinon.assert.calledWith(res.send, '');
    }));
  });
});
books.test.js

import express from 'express';
import models from '../db/models';
const router = express.Router();

var indexPost = async (req, res, next) => {
  try {
    let savedBook = await models.Book.create({
      title: req.body.title || null,
      isbn: req.body.isbn || null,
      author: req.body.author || null
    });
    res.status(201).json({ book: savedBook.id });
  } catch (err) {
    res.status(400).send('');
  }
};
router.post('/', indexPost);

export default router;
export { indexPost };
import { indexPost } from '../../../src/routes/books';
import models from '../../../src/db/models';
import sinon from 'sinon';
import { expect } from 'chai';
import sinonTestFactory from 'sinon-test';

const sinonTest = sinonTestFactory(sinon);

describe('Books router', () => {
  describe('indexPost', () => {
    it('should save the book to the database', sinonTest(async function () {
      let req = {
        body: {
          title: 'Book Title',
          isbn: '123asera23',
          author: 123
        }
      };

      let res = {
        status: status => {},
        json: json => {}
      };

      this.stub(res, 'status').returns(res);
      this.stub(res, 'json').returns(res);

      indexPost(req, res);

      let book = await models.Key.findById(1);

      expect(book.title).to.equal('Book Title');
      expect(book.isbn).to.equal('123asera23');
      expect(book.author).to.equal(123);

      sinon.assert.calledWith(res.status, 201);
      sinon.assert.calledWith(res.json, { book: 1 });
    }));

    it('should throw an error if data is not all there', sinonTest(async function () {
      let req = {
        body: {
          title: 'Book Title',
          author: 123
        }
      };

      let res = {
        status: status => {},
        send: send => {}
      };

      this.stub(res, 'status').returns(res);
      this.stub(res, 'send').returns(res);

      indexPost(req, res);

      sinon.assert.calledWith(res.status, 400);
      sinon.assert.calledWith(res.send, '');
    }));
  });
});
错误

1) Books router
    indexPost
        should throw an error if data is not all there:
            AssertError: expected status to be called with arguments
            at Object.fail (/var/app/node_modules/sinon/lib/sinon/assert.js:96:21)
            at failAssertion (/var/app/node_modules/sinon/lib/sinon/assert.js:55:16)
            at Object.assert.(anonymous function) [as calledWith] (/var/app/node_modules/sinon/lib/sinon/assert.js:80:13)
            at Context.<anonymous> (tests/src/routes/books.test.js:58:20)
            at Generator.next (<anonymous>)
            at step (tests/src/routes/books.test.js:21:191)
            at tests/src/routes/keys.test.js:21:437
            at new Promise (<anonymous>)
            at Context.<anonymous> (tests/src/routes/books.test.js:21:99)
            at callSandboxedFn (/var/app/node_modules/sinon-test/lib/test.js:94:25)
            at Context.sinonSandboxedTest (/var/app/node_modules/sinon-test/lib/test.js:114:24)
1)书籍路由器
indexPost
如果数据不全,则应引发错误:
AssertError:应使用参数调用状态
at Object.fail(/var/app/node_modules/sinon/lib/sinon/assert.js:96:21)
在failAssertion(/var/app/node_modules/sinon/lib/sinon/assert.js:55:16)
在Object.assert.(匿名函数)[调用时](/var/app/node_modules/sinon/lib/sinon/assert.js:80:13)
在上下文中。(tests/src/routes/books.test.js:58:20)
在Generator.next()处
步骤(tests/src/routes/books.test.js:21:191)
at tests/src/routes/keys.test.js:21:437
在新的承诺()
在上下文中。(tests/src/routes/books.test.js:21:99)
在callSandboxedFn(/var/app/node_modules/sinon test/lib/test.js:94:25)
位于Context.sinonSandboxedTest(/var/app/node_modules/sinon test/lib/test.js:114:24)

因为没有人看到这一点来意识到这并不是一个简单的不平等断言,所以我将发布我最终找到的真实答案

基本上,我的测试方法是错误的。我只考虑了javascript中非异步代码的一半

我需要做的是向摩卡的
it
功能返回一个承诺。为了做到这一点,我的控制器还需要回报一个承诺。在做数据库工作的情况下,我可以返回数据库调用承诺

一旦承诺调用了
解析
拒绝
。然后,您可以进行断言,以查看测试是否有效

他们的关键是你必须把你的承诺从控制器的底部一直链接到摩卡的
it
功能

下面是解决此问题的代码

import express from 'express';
import models from '../db/models';
const router = express.Router();

var indexPost = (req, res, next) => {
  return models.Book.create({
    title: req.body.title || null,
    isbn: req.body.isbn || null,
    author: req.body.author || null
  }).then(savedBook => {
    res.status(201).json({ book: savedBook.id });
  }).catch(err => {
    res.status(400).send('');
  });
};
router.post('/', indexPost);

export default router;
export { indexPost };

import { indexPost } from '../../../src/routes/books';
import models from '../../../src/db/models';
import sinon from 'sinon';
import { expect } from 'chai';

describe('Books router', () => {
  describe('indexPost', () => {
    it('should save the book to the database', async () => {
      let req = {
        body: {
          title: 'Book Title',
          isbn: '123asera23',
          author: 123
        }
      };

      const jsonStub = sinon.stub()
      const res = { status: status => ({ json: jsonStub, send: err => err }) }
      const statusSpy = sinon.spy(res, 'status')

      return indexPost(req, res).then(() => {
        let book = await models.Key.findById(1);

        expect(book.title).to.equal('Book Title');
        expect(book.isbn).to.equal('123asera23');
        expect(book.author).to.equal(123);

        sinon.assert.calledWith(res.status, 201);
        sinon.assert.calledWith(res.json, { book: 1 });
      })
    }));

    it('should throw an error if data is not all there', () => {
      let req = {
        body: {
          title: 'Book Title',
          author: 123
        }
      };

      const sendStub = sinon.stub()
      const res = { status: status => ({ json: err => err, send: sendStub }) }
      const statusSpy = sinon.spy(res, 'status')

      indexPost(req, res).then(() => {
        sinon.assert.calledWith(res.status, 400);
        sinon.assert.calledWith(res.send, '');
      });
    }));
  });
});

我的response对象中也有一些奇怪之处,上面的代码也解决了这个问题。

sinon.assert.calledWith(res.status,503)vs.
资源状态(400).send(错误名称)
似乎马上就可疑了。@jonrsharpe以什么方式?在第一次测试中,相同的链式调用可以正常工作。还是我拼错了什么东西却看不见?对那些对我的帖子投了反对票的人来说为什么?我对我的问题是否不够明确?没有足够的例子?不好的标题?因为它们不是相同的状态代码…这不会导致它通过使它们相同。我想我抄错了测试版本。通常,如果只是代码的错配,它会说。“预计503,实际400”之类的。在这种情况下,它甚至似乎没有到达那里。这就像是当抛出并捕获错误时,附加到
res
的函数就消失了。