【问题标题】:Mock a library in jest with Typescript用 Typescript 开玩笑地模拟一个库
【发布时间】:2019-08-30 21:07:22
【问题描述】:

我想模拟一个 GCP 存储桶,但 Typescript 因为打字而大喊大叫。

这是我要测试的类的摘录:

private storage = new Storage({
  projectId: 'PROJECT_NAME',
  keyFilename: env.gcpKeyFilename,
});

get bucket() {
  return this.storage.bucket('fundee-assets');
}

private async _downloadFromBucket(name) {
  const file = this.bucket.file(`${name}`);
  const destination = `${name}`.split('/').pop();
  await file.download({ destination, validation: false });
  return destination;
}

我不想开玩笑地模拟 GCP 存储桶的一部分。所以我尝试了:

jest.spyOn(service, 'bucket', 'get').mockImplementationOnce(
  ()=>{
    return {
      file(name){
        return {
          download(dest, validation){
            return dest;
          }
        };
      }
    }
  }
)

但是 typescript 大喊大叫,因为它没有 GCP Bucket 类型的所有属性:

Type '{ file(name: string): { download(dest: any, validation: any): any; }; }' is missing the following properties from type 'Bucket': name, storage, acl, iam, and 52 more.

关于如何绕过这个或者我做的测试完全错误的任何想法?

【问题讨论】:

    标签: typescript unit-testing google-cloud-platform jestjs


    【解决方案1】:

    这是一个基于以下的解决方案:

    "@google-cloud/storage": "^3.0.2",
    "jest": "^23.6.0",
    "ts-jest": "^23.10.4",
    "typescript": "^3.0.3"
    

    StorageService.ts:

    import { Storage } from '@google-cloud/storage';
    
    class StorageService {
      private storage = new Storage({
        projectId: 'PROJECT_NAME',
        keyFilename: ''
      });
    
      get bucket() {
        return this.storage.bucket('fundee-assets');
      }
    
      private async _downloadFromBucket(name) {
        const file = this.bucket.file(`${name}`);
        const destination = `${name}`.split('/').pop();
        await file.download({ destination, validation: false });
        return destination;
      }
    }
    
    export { StorageService };
    

    单元测试:

    import { StorageService } from './';
    
    const mockedFile = {
      download: jest.fn()
    };
    
    const mockedBucket = {
      file: jest.fn(() => mockedFile)
    };
    
    const mockedStorage = {
      bucket: jest.fn(() => mockedBucket)
    };
    
    const storageService = new StorageService();
    
    jest.mock('@google-cloud/storage', () => {
      return {
        Storage: jest.fn(() => mockedStorage)
      };
    });
    
    describe('StorageService', () => {
      describe('#_downloadFromBucket', () => {
        it('t1', async () => {
          const name = 'jest/ts';
          // tslint:disable-next-line: no-string-literal
          const actualValue = await storageService['_downloadFromBucket'](name);
          expect(mockedBucket.file).toBeCalledWith(name);
          expect(mockedFile.download).toBeCalledWith({ destination: 'ts', validation: false });
          expect(actualValue).toBe('ts');
        });
      });
    });
    

    单元测试结果:

     PASS  src/__tests__/cloud-storage/57724058/index.spec.ts
      StorageService
        #_downloadFromBucket
          ✓ t1 (9ms)
    
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        3.594s, estimated 4s
    

    【讨论】:

    • 非常感谢,它有效!当我尝试类似的事情时,我在 beforeAll 方法中使用了 jest.mock ......似乎不是那样工作的。但是,它在 import 语句之后声明时有效。 ;)
    • @MattWalterspieler 很高兴听到。我不确定在 beforeAll 方法中使用 jest.mock 是否正确。
    • 现在我知道了!
    猜你喜欢
    • 2018-10-23
    • 2017-07-01
    • 1970-01-01
    • 2023-03-08
    • 2020-03-05
    • 1970-01-01
    • 2021-07-03
    • 2019-03-23
    • 2020-11-18
    相关资源
    最近更新 更多