【问题标题】:Mock imported class in typescript with jest用笑话模拟打字稿中的导入类
【发布时间】:2018-11-29 21:17:07
【问题描述】:

我正在尝试使用 jest 在 typescript 类中模拟导入的类,以下代码用于主程序(我从函数内部删除了一些代码,但应该仍然清楚我要做什么)

import * as SocketIO from "socket.io";

import {AuthenticatedDao} from "../../dao/authenticated.dao";

export default class AuthenticationService {
    private readonly _authenticatedDao: AuthenticatedDao = AuthenticatedDao.Instance;
    private readonly _io;

    constructor(socketIo: SocketIO.Server) {
        this._io = socketIo;
    }

    public authenticateUser(username: string, password: string, clientSocketId: string): void {
        this._authenticatedDao.authenticateUser(username, password).then((authenticatedUser) => {

        }).catch(rejected => {

        });
    }
}


import {createServer, Server} from 'http';
import * as express from 'express';
import * as socketIo from 'socket.io';
import {LogincredentialsDto} from "./models/dto/logincredentials.dto";
import {config} from './config/config';
import AuthenticationService from "./services/implementation/authentication.service";
import {Logger} from "./helperclasses/logger";
import {format} from "util";

export class ClassA {
    private readonly _configPort = config.socketServerPort;

    private readonly _logger: Logger = Logger.Instance;
    private _app: express.Application;
    private _server: Server;
    private _io: socketIo.Server;
    private _socketServerPort: string | number;
    private _authenticationService: AuthenticationService;


    constructor() {
        this.configure();
        this.socketListener();
    }

    private configure(): void {
        this._app = express();

        //this._server = createServer(config.sslCredentials, this._app);
        this._server = createServer(this._app);

        this._socketServerPort = process.env.PORT || this._configPort;
        this._io = socketIo(this._server);

        this._server.listen(this._socketServerPort, () => {
            this._logger.log(format('Server is running on port: %s', this._socketServerPort));
        });

        this._authenticationService = new AuthenticationService(this._io);
    }


    private socketListener(): void {
        this._io.on('connection', (client) => {
                client.on('authenticate', (loginCreds: LogincredentialsDto) => {
                    console.log(loginCreds.username, loginCreds.password, client.id);
                    this._authenticationService.authenticateUser(loginCreds.username, loginCreds.password, client.id);
                });
            }
        );
    }
}

我试图在“AuthenticationService”中模拟函数“authenticateUser”,而不是调用我想模拟承诺的普通代码。我尝试使用https://jestjs.io/docs/en/es6-class-mocks 中提供的示例,但是当我尝试执行以下操作时:

import AuthenticationService from '../src/services/implementation/authentication.service';
jest.mock('./services/implementation/authentication.service');

beforeEach(() => {
    AuthenticationService.mockClear();
});

it('test', () => {

    // mock.instances is available with automatic mocks:
    const authServerInstance = AuthenticationService.mock.instances[0];

我收到此错误: 错误:(62, 31) TS2339:“typeof AuthenticationService”类型上不存在属性“mock”。

我在这里做错了什么?我应该以不同的方式模拟类/函数,因为它使用了 Promise 吗?

【问题讨论】:

  • 该错误是 TypeScript 输入错误。你能分享你的测试代码吗?
  • 嗨,Brian,我添加了一小段测试代码的 sn-p,但问题是我无法运行测试,因为我无法模拟类。

标签: typescript unit-testing testing jestjs


【解决方案1】:

问题

AuthenticationService 的输入不包括 mock 属性,因此 TypeScript 会引发错误。


详情

jest.mock 创建一个模块的 automatic mock,“用模拟构造函数替换 ES6 类,并用总是返回 undefined 的模拟函数替换其所有方法”。

在这种情况下,authentication.service.ts 的 default 导出是一个 ES6 类,因此它被替换为模拟构造函数。

模拟构造函数有一个 mock 属性,但 TypeScript 不知道它,仍然将 AuthenticationService 视为原始类型。


解决方案

使用jest.Mocked 让TypeScript 知道jest.mock 引起的打字变化:

import * as original from './services/implementation/authentication.service';  // import module
jest.mock('./services/implementation/authentication.service');

const mocked = original as jest.Mocked<typeof original>;  // Let TypeScript know mocked is an auto-mock of the module
const AuthenticationService = mocked.default;  // AuthenticationService has correct TypeScript typing

beforeEach(() => {
  AuthenticationService.mockClear();
});

it('test', () => {

    // mock.instances is available with automatic mocks:
    const authServerInstance = AuthenticationService.mock.instances[0];

【讨论】:

  • 感谢您的帮助,通过使用您的代码,我了解了如何在类中模拟函数,感谢您提供详细信息,现在更清楚了。
  • @brian-lives-outdoors 我试过这个,但由于某种原因打字稿仍然将 Mocked 实例视为它正在模拟的实际类型......有什么想法吗? (试图模拟一个界面)
  • 这实际上对我不起作用,因为 TypeScript 告诉我需要先将其转换为未知数。即original as unknown as jest.Mocked&lt;typeof original&gt;有谁知道解决这个问题的方法吗?
  • 这对我不起作用。 AuthenticationService.mockClear();生成 -> 属性 mockClear 在 bla bla 中不存在。检查它具有 mockClear、mock 等的对象。但是 typescript 不知道这些类型。
  • 我不得不用const AuthenticationService = mocked.AuthenticationService 替换const AuthenticationService = mocked.default;,然后它对我有用。我正在使用 ts-jest 25.2.1。
猜你喜欢
  • 1970-01-01
  • 2018-12-15
  • 2018-09-16
  • 2019-02-06
  • 1970-01-01
  • 2017-12-10
  • 2020-12-19
  • 2019-09-13
  • 2018-06-21
相关资源
最近更新 更多