使用Jasmine和TypeScript进行单元测试

62

我正试图编写一个使用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");
    });
});

然而,import语句有一个红色的波浪线,并显示错误消息“无法解析外部模块../../../scripts/typings/jasmine/jasmine,模块不能别名为非模块类型”。

您有什么想法是什么导致了这个错误?我已经检查了我的项目构建设置中的“模块系统”选项是否设置为AMD。我还检查了jasmine.d.ts中是否定义了jasmine模块。我从DefinitelyTyped网站下载了这个文件。

declare module jasmine {
    ...
}

1
es6: import Jasmine from 'path/here';. es5: var Jasmine = require('path/here');. 请使用 beforeEachitexpect,而不是 BeforeEachItExpect - marcel
谢谢您的回复。我认为在Typescript中以下代码是有效的:import Jasmine = require("...")。但是,可能不是这样,因为它会给出很多编译错误... - aw1975
8个回答

77

以下是我认为的截至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应用而不是Node应用程序,则应该使用Karma而不是Jasmine CLI来运行测试。


当我尝试这样做时,我遇到了与其他任何教程如何做此操作时相同的问题:“ReferenceError: define未定义”。我认为这要么是因为我正在使用webpack,要么是因为它是vss sdk web扩展。 - pabrams
1
这个方法适用于没有webpack的普通ts-node测试。如果你想要webpack,你应该使用karma。 - AJ Richardson
2
如果您需要向Jasmine提供参数:"test": "ts-node --project ./tsconfig-server.json node_modules/jasmine/bin/jasmine --config=jasmine.json", - Adrian Moisa
5
对于像我这样的Jasmine新手,您需要更改jasmine.json以捕获*.ts文件而不是*.js文件。 - Dave Potts
当您使用此示例并安装eslint时,将无法编译任何此代码。Jasmine类型将不可用。 - Daniel Kaplan
尝试使用以下命令来跳过类型错误: "test": "node -r ts-node/register/transpile-only node_modules/jasmine/bin/jasmine --config=jasmine.json" - Fabio Ribeiro de Carvalho

9
将以下内容放在你的 TypeScript 规范文件的顶部:
/// <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模块从命令行运行您的spec文件。全局安装这些命令行工具:
$ 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浏览器中运行它。同样的TypeScript代码。


jasmine-ts 的问题在于它基于 Jasmine 2,因此您无法使用最新和最棒的 Jasmine 3 功能。我希望他们能解决这个问题。在 GitHub 上有一个开放的票据:https://github.com/svi3c/jasmine-ts/issues/27 - Benny Code
2
@BennyNeugebauer中的“they”=我们,因为这是开源社区。所以任何需要它的人都可以对其进行改进,我鼓励你这样做,因为这肯定会是一个有益的改进! - Yavin5
原始的 jasmine-ts(https://www.npmjs.com/package/jasmine-ts)已经不再积极维护,但是 ert78gb 的分支(https://www.npmjs.com/package/@ert78gb/jasmine-ts)是活跃的。原始的 jasmine-ts 在其依赖项中存在安全漏洞,但是 ert78gb 的分支没有。我建议这样安装 jasmine-ts:npm install -save-dev @ert78gb/jasmine-ts - Jan Van Bruggen
1
原始的jasmine-ts(npmjs.com/package/jasmine-ts)现在由ert78gb积极维护!我现在建议按照原始方式安装jasmine-ts:npm install -save-dev jasmine-ts。目前,我无法编辑此帖子以撤销我的更改,因为“建议的编辑队列已满”... :( - Jan Van Bruggen

5

如果你在导入时遇到问题,请使用tsconfig-paths

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

运行启用了TypeScript的Jasmine:

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

确保Jasmine可以搜索.ts文件:

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

如果您在项目中使用脚本,则可能需要使用polyfills来测试您的脚本。创建一个带有所需导入的辅助文件,例如helpers/global/polifill.ts

import 'core-js';

4
对我来说,我做了以下事情:
安装Typings
npm install typings --global

然后为Jasmine添加输入类型。
typings install dt~jasmine --save --global

3
你真的不应该再使用typings了。更好的方法是在NPM的@types/*存储库中使用类型定义。 - jonnysamps

4
您可以尝试使用一个仅产生副作用的导入,它会引入@types/jasmine声明,并将jasmine函数放置到全局范围内,这样您就无需在每个调用前加前缀jasmine.,从而可以快速移植现有的单元测试,并且仍然与webpack很好地兼容。
// tslint:disable-next-line:no-import-side-effect
import "jasmine";

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

当然,您仍需要安装Jasmine和对应的类型文件:
$ 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文件位于名为“test”的子目录中,编译到bin/test,并且您有一个test/support/jasmine.json文件,其中包含以下内容:
{
    "spec_dir": "bin/test",
    "spec_files": [
      "**/*[sS]pec.js"
    ],
    "stopSpecOnExpectationFailure": false,
    "random": false
}

另外,以上所有方法在Windows系统上也适用


3
将此内容包含在您的jasmine html文件中,...
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine.js"></script>

...或者安装npm jasmine包:

npm install --save-dev jasmine

如果您使用第二种方式(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'。”有任何想法出了什么问题? - ryanwebjackson

0
你没有要求这个,但是为了得到额外的分数:一旦你使用ts-node调用Jasmine启动脚本并且让AJ的答案正常工作,你就可以添加一个新任务:
"scripts": {
  "watch": "ts-node-dev --respawn -- ./node_modules/jasmine/bin/jasmine src/**.spec.ts"
}

当然,如果你愿意,你可以使用Jasmine的配置文件来传递你的规格或任何其他参数。现在,Jasmine将运行所有的规格一次,然后ts-node-dev将在后台等待你的测试或者它们可能require的任何变化,此时jasmine将再次运行。我还没有找到一种只运行已更改的测试(或导入已更改的测试)的方法 - 据我所知,这也不被支持;


0

我的文件夹结构

规范文件夹位于项目根目录下

    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"
}

将行"/spec/dist"添加到.gitignore

运行您的测试!

使用npm test运行您的测试。

它是如何工作的?

  1. 测试目录被清除。
  2. 测试被编译为JS并放置在spec / dist文件夹中。
  3. 从此位置运行测试。

希望对您有所帮助。好好编程。


截至2022年,jasmine-console-reporter已经有大约6年没有更新了。如果你的nodejs项目使用了新的import语法(ES6+模块),它将无法工作。 - Joe Coder
谢谢,你有其他的选择吗? - Vladimír Mlázovský
1
最终我使用了 ts-node 直接运行 TypeScript 文件,就像其他答案中描述的那样。 - Joe Coder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接