
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
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。
特性
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() {
}
}
不依赖当前项目的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));
}
}
$ 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 - /
7/20| Annotation | Description | isSupported |
|---|---|---|
|
|
Denotes that a method is a test method. Unlike JUnit 4’s | ✅ |
|
|
Denotes that a method is a parameterized test. Such methods are inherited unless they are overridden. | ❌ |
|
|
Denotes that a method is a test template for a repeated test. Such methods are inherited unless they are overridden. | ❌ |
|
|
Denotes that a method is a test factory for dynamic tests. Such methods are inherited unless they are overridden. | ❌ |
|
|
Denotes that a method is a template for test cases designed to be invoked multiple times depending on the number of invocation contexts returned by the registered providers. Such methods are inherited unless they are overridden. | ❌ |
|
|
Used to configure the test method
execution order for the annotated test class; similar to JUnit 4’s
| ❌ |
|
|
Used to configure the test instance lifecycle for the annotated test class. Such annotations are inherited. | ❌ |
|
|
Declares a custom display name for the test class or test method. Such annotations are not inherited. | ✅ |
|
|
Declares a custom display name generator for the test class. Such annotations are inherited. | ❌ |
|
|
Denotes that the annotated method should be executed before
each | ✅ |
|
|
Denotes that the annotated method should be executed after
each | ✅ |
|
|
Denotes that the annotated method should be executed before
all | ✅ |
|
|
Denotes that the annotated method should be executed after
all | ✅ |
|
|
Denotes that the annotated class is a non-static nested test class. | ❌ |
|
|
Used to declare tags for filtering tests, either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4. Such annotations are inherited at the class level but not at the method level. | ❌ |
|
|
Used to disable a test class or test
method; analogous to JUnit 4’s | ✅ |
|
|
Used to fail a test, test factory, test template, or lifecycle method if its execution exceeds a given duration. Such annotations are inherited. | ❌ |
|
|
Used to register extensions declaratively. Such annotations are inherited. | ❌ |
|
|
Used to register extensions programmatically via fields. Such fields are inherited unless they are shadowed. | ❌ |
|
|
Used to supply a temporary directory via field
injection or parameter injection in a lifecycle method or test method; located in the
| ❌ |
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
FAQs
use junit descrator with typescript
We found that ts-junit demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.