javascript 尝试存根函数会导致属性的描述符不可配置且不可写

3j86kqsm  于 2023-01-08  发布在  Java
关注(0)|答案(3)|浏览(134)

我尝试编写一个单元测试,从@aws-sdk/s3-request-presigner包中存根getSignedUrl函数,但是当我尝试使用sinon存根函数时,收到错误:

  • TypeError:属性getSignedUrl的描述符不可配置且不可写
const s3RequestSigner = require("@aws-sdk/s3-request-presigner");
const expect = require('chai').expect;
const sinon = require('sinon')
....
it('should throw an error when getSignedUrl rejects', async function() {
  const sandbox = sinon.createSandbox();
  sandbox.stub(s3RequestSigner, "getSignedUrl").rejects("fakeUrl");
  sandbox.restore();
})

我正在使用node.js16,写javascript而不是typescribe。有没有办法模拟我的函数,我正在努力写我的测试呢?

sshcrbum

sshcrbum1#

对于ES6模块,我提出了以下解决方案:您可以将getSignedUrl封装在自己的模块中,然后模拟该模块,这种方法适用于sinon无法模拟"不可配置且不可写"方法的任何模块。
例如:

  • my-s3-client-internals. js *-您的定制 Package 器模块
// You'll need to import the original method, assign it to
// a new const, then export that const
import { getSignedUrl as getSignedUrl_orig } from '@aws-sdk/s3-request-presigner';

export const getSignedUrl = getSignedUrl_orig;
  • my-s3-客户端. js *-getSignedUrl的使用者
// Import the method instead from your custom file
import { getSignedUrl } from './my-s3-client-internals';

// Call it however you normally would, for example:
export const getUrl(bucket, key) {
  const command = new GetObjectCommand({ Bucket: bucket, Key: key });
  return getSignedUrl(client, command, { expiresIn: 300 });
}
  • my-s3-client.spec.js *-使用者模块的单元测试
import { getUrl } from './my-s3-client';
import * as clientInternals from './my-s3-client-internals';
import sinon from 'sinon';

it('does something', () => {
  // Mock the method exported from your wrapper module
  sinon.stub(clientInternals, 'getSignedUrl')
    .callsFake(async (client, command, options) => {
      return 'fake-url';
    });

  // Then call your consumer method to test
  const url = await getUrl('test-bucket', 'test-key');
  expect(url).to.equal('fake-url');
});
kmpatx3s

kmpatx3s2#

所以我不会把这个作为官方答案,除非没有更好的解决方案,但这是我的研究带来的解决方案。
该问题与此相关:https://github.com/sinonjs/sinon/issues/2377
其中,当对象描述符不可配置时,sinon将抛出错误。
目前还没有明显的解决方法,我可以找到。解决它的方法是使用proxyquire:

const sinon = require('sinon')
const proxyquire =  require('proxyquire')
...
it('should throw an error when getSignedUrl rejects', async function() {
    const fakeurl = 'hello world'
    const fakeURL = sinon.stub().resolves(fakeurl)
    const handler = proxyquire(
      '../../handlers/presigned_url',
      {
        '@aws-sdk/s3-request-presigner': {
          'getSignedUrl': async () => {
            return fakeURL()
          }
        }
      }
    )

这将解析为您想要的fakeurl

093gszye

093gszye3#

另一种可能的解决方案是使用mockery,例如模拟uuid

import { expect } from 'chai';
import mockery from 'mockery';
import sinon from 'sinon';

describe('domain/books', () => {
  let createBook;
  let uuidStub;

  before(async () => {
    mockery.enable({
      warnOnReplace: false,
      warnOnUnregistered: false,
    });
    uuidStub = sinon.stub();
    mockery.registerMock('uuid', { v4: uuidStub });

    ({ createBook } = await import('../domain/books.js'));
  });

  afterEach(() => {
    sinon.resetHistory();
  });

  after(() => {
    sinon.restore();
    mockery.disable();
    mockery.deregisterAll();
  });

  describe('createBook', () => {
    it('should save a book and return the id', () => {
      const id = 'abc123';
      uuidStub.returns(id);

      const { id: bookId } = createBook({
        title: 'My Book',
        author: 'Jane Doe',
      });
      expect(bookId).to.equal(id);
    });
  });
});

嘲弄设置有点繁琐,但图书馆救了我很多次。

相关问题