1.0.18 • Published 2 years ago

ts-junit v1.0.18

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

ts-junit

use JUnit 5 Decrator with TypeScript

在我看来,在TypeScript里使用面向对象是很大概率变成最常用的方式的。目前所有的JavaScript测试都是面向过程的,比如qunit、jest、mocha、ava、tape等测试框架实现,还是围绕在面向过程阶段。我以为这不是TypeScript在现实中该有的样式。

我对Java还算熟悉,比如使用JUnit 5的测试代码就是采用面向对象写法的,代码如下。

import static org.junit.jupiter.api.Assertions.assertEquals;

import example.util.Calculator;

import org.junit.jupiter.api.Test;

class MyFirstJUnitJupiterTests {

    private final Calculator calculator = new Calculator();

    @Test
    void addition() {
        assertEquals(2, calculator.add(1, 1));
    }

}

这种写法是非常简单的,这就是Java面向的好处。如果换成TypeScript,几乎可以保持写法一模一样,代码如下。

import assert from 'assert'
import { Test } from 'ts-junit'

export default class MyFirstJUnitJupiterTests  {

  calculator = new Calculator();

  @Test
  void addition() {
    assert.is(2, calculator.add(1, 1));
  }

}

反观前端的测试代码基本上2种风格。前端的测试代码风格1,它是最常用的测试方式,代码实例如下。

test('JSON', () => {
  const input = {
    foo: 'hello',
    bar: 'world'
  };

  const output = JSON.stringify(input);

  assert.snapshot(output, `{"foo":"hello","bar":"world"}`);
  assert.equal(JSON.parse(output), input, 'matches original');
})

前端的测试代码风格2,bdd风格,它更强调行为对测试用例的影响,代码实例如下。

describe('User', function(){
  describe('#save()', function(){
    it('should save without error', function(done){
      var user = new User('Luna');
      user.save(function(err){
        if (err) throw err;
        done();
      });
    })
  })
})

对比一下Java和JavaScript测试多个写法之后,你会发现,面向对象在JavaScript(TypeScript)里根本不是一等公民。于是我就蒙发了一个想法,想用TypeScript实现一下JUnit。

特性

  • jest 支持 ts 需要引入babel
  • ts-jest 直接支持ts,测试语法上是jest语法,suite/test或describe/it
  • ts-junit 使用junit 5的装饰器进行封装,成熟,使用于熟悉OO的开发,尤其对Java开发更友好。
  • ts-junit 默认使用uvu,同时提供各个常见测试框架的支持,比如jest、mocha、ava、tape、qunit、jasmine等。

示例

import assert from 'assert'
import { BeforeAll, BeforeEach, Disabled, Test, AfterEach, AfterAll } from 'ts-junit'

export default class MyFirstJUnitJupiterTests {
    calculator = new Calculator()

    @BeforeAll
    static void initAll() {
    }

    @BeforeEach
    void init() {
    }

    @Test
    void succeedingTest() {
    
    }

    @Test
    void failingTest() {
        assert.fail("a failing test");
    }

    @Test
    @Disabled("for demonstration purposes")
    void skippedTest() {
        // not executed
    }

    @Test
    void abortedTest() {
        assert.assumeTrue("abc".contains("Z"));
        assert.fail("test should have been aborted");
    }

    @AfterEach
    void tearDown() {
    }

    @AfterAll
    static void tearDownAll() {
    }
}

Usages

方式1: 使用独立cli进行编译

不依赖当前项目的ts环境,直接通过cli执行,参考源码中tests目录下的文件。

$ npm i --global ts-juint
$ junit tests
$ junit tests/test.ts

编写第一个测试用例

import assert from 'assert'
import { Test } from 'ts-junit'

export default class MyFirstJUnitJupiterTests  {

    calculator = new Calculator();

    @Test
    void addition() {
        assert.is(2, calculator.add(1, 1));
    }

}

方式2: 依赖当前项目的ts环境进行编译

$ npm i --save-dev ts-juint

编写测试入口文件ts-junit.ts,文件内指定测试文件或测试目录即可。

import * as path from "node:path";
import { run } from "ts-junit";

const folder = path.resolve(process.cwd(), "./tests");
const file = path.resolve(process.cwd(), "./tests/test.ts");

run([folder, file]);

创建编译时的 tsconfig.json 文件

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es2017",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./build",
    "rootDir": "./src",
    "typeRoots": [],
    "types": [],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "exclude": ["node_modules"],
  "include": ["./src/**/*.ts", "./test/**/*.ts"]
}

编辑 package.json 的启动和编译脚本

{
  "scripts": {
    "test": "NODE_ENV=dev ts-node --project tsconfig.json --files ts-junit.ts",
    "build": "tsc"
  }
}

启动服务

$ npm test
> NODE_ENV=dev ts-node --project tsconfig.json --files ts-junit.ts
[2020-9-1 19:52:12] [debug] [init] [router] get - /

装饰器

TODO

1) 结合 https://github.com/midwayjs/injection 更简单(暂未实现)

class Test {
  @Inject()
  helloTest: IHelloTest;
  @Inject()
  helloService: IHelloService;

  @Before()
  before() {
    mock(helloTest, 'sayhello', () => {
      return 'mocked'
    });
  }

  @Test()
  async test() {
    expect(this.helloTest.sayhello()).eq('mocked');
    
    expect(this.helloService.sayhello('test')).eq('hello test');
  }
}

2) use vm2 with require from memfs

1.0.18

2 years ago

1.0.17

2 years ago

1.0.16

2 years ago

1.0.11

2 years ago

1.0.10

2 years ago

1.0.15

2 years ago

1.0.14

2 years ago

1.0.13

2 years ago

1.0.12

2 years ago

1.0.9

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.3

3 years ago

1.0.0

4 years ago