【问题标题】: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.tsdefault 导出是一个 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
相关资源
最近更新 更多