使用 Jasmine 和 TypeScript 进行单元测试

Posted

技术标签:

【中文标题】使用 Jasmine 和 TypeScript 进行单元测试【英文标题】:Unit testing using Jasmine and TypeScript 【发布时间】:2015-09-01 00:49:49 【问题描述】:

我正在尝试使用 Jasmine 编译一个用 Typescript 编写的单元测试。在我的单元测试文件中包含以下内容后,Resharper 会提示我一个从 jasmine.d.ts 导入类型的链接。

/// <reference path="sut.ts" />
/// <reference path="../../../scripts/typings/jasmine/jasmine.d.ts" />

describe("Person FullName", function () 
    var person;

    BeforeEach(function () 
        person = new Person();
        person.setFirstName("Joe");
        person.setLastName("Smith");
    );

    It("should concatenate first and last names", function () 
        Expect(person.getFullName()).toBe("Joe, Smith");
    );
);

所以我点击链接并得到以下结果(实际上 resharper 只在 describe 函数前加上了“Jasmine.”,所以我手动为其他 Jasmine 调用添加了前缀):

/// <reference path="sut.ts" />
/// <reference path="../../../scripts/typings/jasmine/jasmine.d.ts" />
import Jasmine = require("../../../Scripts/typings/jasmine/jasmine");

Jasmine.describe("Person FullName", function () 
    var person;

    Jasmine.BeforeEach(function () 
        person = new Person();
        person.setFirstName("Joe");
        person.setLastName("Smith");
    );

    Jasmine.It("should concatenate first and last names", function () 
        Jasmine.Expect(person.getFullName()).toBe("Joe, Smith");
    );
);

但是,导入语句有一条红色波浪线,带有错误消息“无法解析外部模块../../../scripts/typings/jasmine/jasmine。模块不能别名为非模块类型”

知道是什么导致了这个错误吗?我检查了我的项目构建设置中的“模块系统”选项是否设置为 AMD。我还检查了 jasmine 模块是否在 jasmine.d.ts 中定义。我从DefiniteTyped 网站下载了这个文件。

declare module jasmine 
    ...

【问题讨论】:

es6:import Jasmine from 'path/here';。 es5:var Jasmine = require('path/here');。使用beforeEachitexpect 而不是BeforeEachItExpect 感谢您的回复。我认为在打字稿中以下是有效的?进口茉莉花 = 要求(“...”)。虽然可能不是因为它给出了这么多编译错误...... 【参考方案1】:

将此添加到您的 jasmine html 文件中,...

<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine.js"></script>

...或安装 npm jasmine 包:

npm install --save-dev jasmine

当您使用第二种方式(茉莉花作为模块)时,您必须导入它:

var jasmine = require('jasmine');

import jasmine from 'jasmine';

然后更改其他代码:

jasmine.describe("Person FullName", function () 
    var person;

    jasmine.beforeEach(function () 
        person = new Person();
        person.setFirstName("Joe");
        person.setLastName("Smith");
    );

    jasmine.it("should concatenate first and last names", function () 
        jasmine.expect(person.getFullName()).toBe("Joe, Smith");
    );
);

我个人更喜欢不使用 jasmine npm 模块的第一种方式。 (我还没有测试模块)

【讨论】:

我收到“类型 'typeof jasmine' 上不存在属性 'describe'。”关于出了什么问题的任何想法?【参考方案2】:

对我来说,我做了以下事情:

安装类型

npm install typings --global

然后为 jasmine 添加输入

typings install dt~jasmine --save --global

【讨论】:

你真的不应该再使用typings了。在 NPM 中使用 @types/* 存储库中的类型定义要好得多。【参考方案3】:

把它放在你的打字稿规范文件的顶部:

/// <reference path="../../node_modules/@types/jasmine/index.d.ts" />
let Jasmine = require('jasmine');

您必须安装以下 Jasmine 模块才能使其工作:

$ npm install jasmine-core jasmine @types/jasmine @ert78gb/jasmine-ts --save-dev

一旦你这样做了,IDE(比如 WebStorm)就会识别 Jasmine 和它的函数,比如 describe()、it() 和 expect().. 所以你不需要在它们前面加上 "Jasmine. "此外,您可以使用 jasmine-ts 模块从命令行运行您的规范文件。全局安装这些命令行工具:

$ npm install -g jasmine @ert78gb/jasmine-ts

然后配置“jasmine”命令行模块,让Jasmine可以找到它的配置文件。然后你应该能够运行 jasmine-ts 并且你的规范文件应该可以从命令行运行:

./node_modules/.bin/jasmine-ts src/something.spec.ts

.. 而且,您也可以将 IDE 配置为这样运行它,并且以这种方式运行调试也应该可以工作(对我有用)。

以这种方式编写测试,您可以在没有 Karma 的情况下在服务器端运行 Jasmine 测试规范,或者使用 Karma 在 Web 浏览器中运行它。相同的打字稿代码。

【讨论】:

jasmine-ts的问题是它基于Jasmine 2,所以你不能使用最新最好的Jasmine 3功能。我希望他们能把它整理好。在 GitHub 上有一张公开的票:github.com/svi3c/jasmine-ts/issues/27 @BennyNeugebauer “他们” = 我们,因为它是开源社区。所以任何需要它的人都可以改进它,我鼓励你,因为是的,这肯定会是一个有益的改进! 原来的 jasmine-ts (npmjs.com/package/jasmine-ts) 没有被积极维护,但是 ert78gb 的 fork (npmjs.com/package/@ert78gb/jasmine-ts) 是。原来的 jasmine-ts 依赖有安全漏洞,而 ert78gb 的 fork 没有。我建议像这样安装 jasmine-ts:npm install -save-dev @ert78gb/jasmine-ts 原始 jasmine-ts (npmjs.com/package/jasmine-ts) 现在得到积极维护,感谢 ert78gb!我现在建议以原始方式安装 jasmine-ts:npm install -save-dev jasmine-ts 我目前无法编辑此帖子以恢复我的更改,因为“建议的编辑队列已满”... :(【参考方案4】:

这是(在我看来)截至 2018 年测试 ts-node 应用程序的最佳方法:

npm install --save-dev typescript jasmine @types/jasmine ts-node

package.json:


  "scripts": 
    "test": "ts-node node_modules/jasmine/bin/jasmine"
  

jasmine.json 中将文件模式更改为*.ts

"spec_files": ["**/*[sS]pec.ts"],

在您的规范文件中:

import "jasmine";
import something from "../src/something";

describe("something", () => 
    it("should work", () => 
        expect(something.works()).toBe(true);
    );
);

运行测试:

npm test

这将使用本地安装的ts-nodejasmine 版本。这比使用全局安装的版本要好,因为使用本地版本,您可以确保每个人都使用相同的版本。

注意:如果您有一个 Web 应用而不是节点应用,您可能应该使用 Karma 而不是 Jasmine CLI 运行测试。

【讨论】:

当我尝试这个时,我遇到的问题与我按照任何其他关于如何执行此操作的教程时遇到的问题相同:“ReferenceError:未定义定义”。我认为这要么是因为我使用的是 webpack,要么是因为它是一个 vss sdk 网络扩展。 这个方法适用于普通的 ts-node 测试(没有 webpack)。如果你想要 webpack,你应该使用 karma。 如果您需要为 jasmine 提供参数:"test": "ts-node --project ./tsconfig-server.json node_modules/jasmine/bin/jasmine --config=jasmine.json", 对于像我这样的 Jasmine 新手,您需要更改 jasmine.json 以获取 *.ts 文件而不是 *.js 文件。 当你使用这个例子并安装 eslint 时,这些代码都不会编译。 Jasmine 类型将不可用。【参考方案5】:

如果您有导入问题,请使用tsconfig-paths

npm i ts-node tsconfig-paths types/jasmine jasmine --save-dev

运行支持打字稿的茉莉花:

ts-node -r tsconfig-paths/register node_modules/jasmine/bin/jasmine.js

确保您的 jasmine 将搜索 .ts 文件:

"spec_files": [
    "**/*[sS]pec.ts"
],
"helpers": [
    "helpers/**/*.ts"
],

要测试您的脚本,如果您在项目中使用它们,您可能还需要 polyfill。创建一个包含所需导入的帮助文件,例如 helpers/global/polifill.ts

import 'core-js';

【讨论】:

【参考方案6】:

您可以尝试 side-effect only import,它会引入 @types/jasmine 声明并将 jasmine 函数置于全局范围内,因此您无需在每个调用前加上 jasmine.允许从现有的单元测试中快速移植,并且仍然可以与 webpack 配合使用。

// tslint:disable-next-line:no-import-side-effect
import "jasmine";

describe("My Unit Test", () =>  /* ... */  );

当然你还需要安装jasmine和typings:

$ npm i jasmine @types/jasmine --save-dev

但是对于 ts 或 node 不需要专门的 jasmine 加载器。只需对已编译的 js 文件运行 jasmine:

$ node ./node_modules/jasmine/bin/jasmine.js --config=test/support/jasmine.json

假设您的 typescript 文件位于编译为 bin/test 的“测试”子目录中,并且您有一个 test/support/jasmine.json ,内容如下:


    "spec_dir": "bin/test",
    "spec_files": [
      "**/*[sS]pec.js"
    ],
    "stopSpecOnExpectationFailure": false,
    "random": false

附:以上所有方法也适用于 Windows

【讨论】:

【参考方案7】:

您不是要求这个,而是要加分:一旦您启动并运行 AJ 的答案(使用 ts-node 调用 Jasmine 启动脚本),您可以添加一个新任务:

"scripts": 
  "watch": "ts-node-dev --respawn -- ./node_modules/jasmine/bin/jasmine src/**.spec.ts"

当然,如果您愿意,您可以使用 Jasmine 的配置文件来传递您的规范或任何其他参数。现在,Jasmine 将运行一次您的所有规范,然后ts-node-dev 将在后台等待您的测试或任何他们可能有require'd 更改,此时jasmine 将再次运行。我还没有找到只运行已更改的测试(或导入已更改的测试)的方法——据我所知,这是not supported anyway;

【讨论】:

【参考方案8】:

我的文件夹结构

Spec 文件夹位于项目的根目录

    spec
      \- dist              // compiled tests
      \- helpers           // files modified testing env
         \- ts-console.ts  // pretty prints of results
      \- support
         \- jasmine.json
      \- YourTestHere.spec.ts
      \- tsconfig.json     // tsconfig for your tests

文件内容

ts-console.ts

const TSConsoleReporter = require("jasmine-console-reporter");
jasmine.getEnv().clearReporters();
jasmine.getEnv().addReporter(new TSConsoleReporter());

jasmine.json


  "spec_dir": "spec/dist",
  "spec_files": [
     "**/*[sS]pec.js"
  ],
  "helpers": [
    "spec/helpers/**/*.js"
  ],
  "stopSpecOnExpectationFailure": false,
  "random": true

package.json

中有额外的脚本
"scripts": 
  "test": "rm -rf ./spec/dist && tsc -p ./spec && jasmine"

并在 .gitignore

中添加“/spec/dist”行

运行你的测试!

使用npm test 运行您的测试。

它是如何工作的?

    测试目录已清理。 测试被编译到 JS 的 spec/dist 文件夹中。 从该位置运行测试。

希望对你有所帮助。良好的编码。

【讨论】:

截至 2022 年,jasmine-console-reporter 大约有 6 年没有更新了。如果您的 nodejs 项目使用较新的 import 语法(ES6+ 模块),它将无法工作。 谢谢,您还有其他选择吗? 我最终使用 ts-node 直接运行 TypeScript 文件,如另一个答案中所述。

以上是关于使用 Jasmine 和 TypeScript 进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

使用 karma-jasmine 和 istanbul 的 Typescript 代码覆盖率

使用 karma-jasmine 和 istanbul 的 Typescript 代码覆盖率

如何测试使用 jasmine + TypeScript 使用常量调用的函数

如何在 Visual Studio Code 中使用 Typescript 和 Jasmine 框架编写 Protractor 测试脚本?

Jasmine:Angular Typescript 项目中的“不完整:未找到规范”

单元测试 typescript 指令模板 karma-jasmine,html 未定义