使用Jest模拟es6类静态方法

8nuwlpux  于 2023-02-06  发布在  Jest
关注(0)|答案(1)|浏览(185)

我真的很难处理这个问题。我读了很多jest文档,也读了很多其他的文章,但是还没有什么能帮助我,甚至chatGPT。
我在试着测试这个类。

export class CookiesManager extends Auth {
  static get(key: string) {
    return this.cookies.get(key);
  }

  static set(key: string, value: any, config?: CookieSetOptions) {
    this.cookies.set(key, value, config || this.config);
  }

  static remove(key: string) {
    const { hostname } = new URL(`${process.env.WEB_HOST}`);

    this.cookies.remove(key, { ...this.config, domain: hostname });
  }
}

这是Auth类,但在我的例子中,我甚至还没有到达这里,或者我想我不需要在这个范围内处理这部分,无论如何,只是作为参考。

import moment from 'moment';
import Cookies, { CookieSetOptions } from 'universal-cookie';

export class Auth {
  static cookies = new Cookies();

  static config: CookieSetOptions = {
    path: '/',
    maxAge: 1800,
    expires: moment().add(30, 'm').toDate(),
    secure: process.env.NODE_ENV !== 'development',
  };

  static setToken(token: string) {
    token && this.cookies.set('auth_token', token, this.config);
  }

  static getToken() {
    return this.cookies.get('auth_token');
  }

  static clear() {
    this.cookies.remove('auth_token', this.config);
  }
}

我已经为CookiesManager类编写了模拟。该模块还有其他命名的导出。

jest.mock('core/utils/storage-manager.ts', () => {
      const originalClasses = jest.requireActual('core/utils/storage-manager.ts');
    
      class CookiesManagerMock {
        static config = {
          path: '/',
          maxAge: 1800,
        }
    
        static set = jest.fn().mockImplementation((key, value, config) => {
          console.log('Mock set called');
          mockCookies[key] = value;
        })
    
        static get = jest.fn().mockImplementation((key) => {
          console.log('Mock get called');
          return mockCookies[key];
        })
    
        static remove = jest.fn().mockImplementation((key, config) => {
          console.log('Mock remove called');
          delete mockCookies[key];
        })
      }
    
      return {
        ...originalClasses,
        CookiesManager: CookiesManagerMock,
      }
    })

这是测试块。

describe('CookiesManager', () => {
    afterEach(() => {
      jest.restoreAllMocks();
    });

    test('It should set a cookie', () => {
      CookiesManager.set('test_key', 'test_value');
      console.log(mockCookies.test_key, 'mockCookies')
      expect(CookiesManager.set).toHaveBeenCalledWith('test_key', 'test_value');
    });

    test('It should get a cookie', () => {
      CookiesManager.get.mockReturnValueOnce('test_value');
      expect(CookiesManager.get('test_key')).toEqual('test_value');
      expect(CookiesManager.get).toHaveBeenCalledWith('test_key');
    });

    test('It should remove a cookie', () => {
      CookiesManager.remove('test_key');
      expect(CookiesManager.remove).toHaveBeenCalledWith('test_key');
    });
})

已更新

即使测试通过了,模拟类中也没有console.log语句被调用。而且mockCookies总是空的。我对CommonJS modules做了同样的尝试,奇怪的是console.log语句被调用了。
在笑话里,写得很清楚。

    • 模拟Fn.模拟实现(fn)**

接受应用作模拟实现的函数。模拟本身仍将记录进入的所有调用和来自其本身的示例-唯一的区别是,在调用模拟时也将执行该实现。
也许我搞错了,不明白嘲笑的本质。

wlzqhblo

wlzqhblo1#

你没有正确地模拟静态方法。你正在使用的方法是尝试模拟类的示例方法。这里有一个解决方案,创建一个带有模拟静态方法的模拟CookiesManager类。
storage-manager.ts

type CookieSetOptions = any;

export class CookiesManager {
  static get(key: string) {}

  static set(key: string, value: any, config?: CookieSetOptions) {}

  static remove(key: string) {}
}

export const a = () => 'a'
export const b = () => 'b'

storage-manager.test.ts

import { CookiesManager, a, b } from './storage-manager';

jest.mock('./storage-manager', () => {
  const originalModules = jest.requireActual('./storage-manager');

  const mockCookies = {};
  class CookiesManagerMock {
    static set = jest.fn().mockImplementation((key, value, config) => {
      console.log('Mock set called');
      mockCookies[key] = value;
    });

    static get = jest.fn().mockImplementation((key) => {
      console.log('Mock get called');
      return mockCookies[key];
    });

    static remove = jest.fn().mockImplementation((key, config) => {
      console.log('Mock remove called');
      delete mockCookies[key];
    });
  }
  return {
    ...originalModules,
    CookiesManager: CookiesManagerMock,
  };
});

describe('75323871', () => {
  test('It should set a cookie', () => {
    const config = { path: '/', maxAge: 1800 };
    expect(jest.isMockFunction(CookiesManager.set)).toBeTruthy();
    CookiesManager.set('test_key', 'test_value', config);
    expect(CookiesManager.set).toHaveBeenCalledWith('test_key', 'test_value', config);
    expect(CookiesManager.get('test_key')).toBe('test_value');

    // other named exports
    expect(a()).toBe('a');
    expect(b()).toBe('b');
  });
});

jest.config.js

module.exports = {
  preset: 'ts-jest/presets/js-with-ts'
};

试验结果:

PASS  stackoverflow/75323871/storage-manager.test.ts (8.614 s)
  75323871
    ✓ It should set a cookie (17 ms)

  console.log
    Mock set called

      at Function.<anonymous> (stackoverflow/75323871/storage-manager.test.ts:9:15)

  console.log
    Mock get called

      at Function.<anonymous> (stackoverflow/75323871/storage-manager.test.ts:14:15)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.358 s, estimated 10 s
  • 注意 *:也许jest.spyOn(CookiesManager, 'set').mockImplementation()是一个更好的解决方案,您只需要模拟特定的静态方法。请参见www.example.comhttps://jestjs.io/docs/es6-class-mocks#static-getter-and-setter-methods

软件包版本:

"jest": "^26.6.3",
"ts-jest": "^26.4.4"

相关问题