{"id":15017379,"url":"https://github.com/i5ting/ts-junit","last_synced_at":"2025-10-29T16:24:33.161Z","repository":{"id":57380835,"uuid":"257549030","full_name":"i5ting/ts-junit","owner":"i5ting","description":"use JUnit 5 Decorator in TypeScript","archived":false,"fork":false,"pushed_at":"2022-11-10T03:59:02.000Z","size":438,"stargazers_count":41,"open_issues_count":6,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-05T08:56:23.905Z","etag":null,"topics":["ava","jasmine","jest","junit","mocha","qunit","tape","test","test-automation","testing","testng"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/i5ting.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-21T09:44:18.000Z","updated_at":"2025-08-08T03:51:00.000Z","dependencies_parsed_at":"2023-01-21T10:04:27.463Z","dependency_job_id":null,"html_url":"https://github.com/i5ting/ts-junit","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/i5ting/ts-junit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i5ting%2Fts-junit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i5ting%2Fts-junit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i5ting%2Fts-junit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i5ting%2Fts-junit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/i5ting","download_url":"https://codeload.github.com/i5ting/ts-junit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i5ting%2Fts-junit/sbom","scorecard":{"id":476417,"data":{"date":"2025-08-11","repo":{"name":"github.com/i5ting/ts-junit","commit":"ac62246408e94bdb3440712e60579032c9d68336"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":5,"reason":"Found 6/11 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/i5ting/ts-junit/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/i5ting/ts-junit/ci.yml/main?enable=pin","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"10 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T15:24:58.490Z","repository_id":57380835,"created_at":"2025-08-19T15:24:58.490Z","updated_at":"2025-08-19T15:24:58.490Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278431610,"owners_count":25985688,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ava","jasmine","jest","junit","mocha","qunit","tape","test","test-automation","testing","testng"],"created_at":"2024-09-24T19:50:22.944Z","updated_at":"2025-10-09T03:14:29.456Z","avatar_url":"https://github.com/i5ting.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ts-junit\n\n![version](https://img.shields.io/npm/v/ts-junit)\n![license](https://img.shields.io/npm/l/ts-junit)\n[![TypeScript](https://img.shields.io/badge/lang-typescript-informational)](https://www.typescriptlang.org)\n![npm total downloads](https://img.shields.io/npm/dt/ts-junit.svg)\n![npm month downloads](https://img.shields.io/npm/dm/ts-junit.svg)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/i5ting/ts-junit/pulls)\n[![Github action](https://github.com/i5ting/ts-junit/actions/workflows/ci.yml/badge.svg)](https://github.com/i5ting/ts-junit/actions/workflows/ci.yml)\n\n\u003e use JUnit 5 Decorator in TypeScript\n\n在我看来，在 TypeScript 里使用面向对象是很大概率变成最常用的方式的。目前所有的 JavaScript 测试都是面向过程的，比如 qunit、jest、mocha、ava、tape 等测试框架实现，还是围绕在面向过程阶段。我以为这不是 TypeScript 在现实中该有的样式。\n\n我对 Java 还算熟悉，比如使用 JUnit 5 的测试代码就是采用面向对象写法的，代码如下。\n\n```Java\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport example.util.Calculator;\nimport org.junit.jupiter.api.Test;\n\nclass MyFirstJUnitJupiterTests {\n\n    private final Calculator calculator = new Calculator();\n\n    @Test\n    void addition() {\n        assertEquals(2, calculator.add(1, 1));\n    }\n}\n```\n\n这种写法是非常简单的，这就是 Java 面向的好处。如果换成 TypeScript，几乎可以保持写法一模一样，代码如下。\n\n```ts\nimport assert from \"assert\";\nimport { Test } from \"ts-junit\";\n\nexport default class MyFirstJUnitJupiterTests {\n  calculator = new Calculator();\n\n  @Test\n  addition() {\n    assert.is(2, calculator.add(1, 1));\n  }\n}\n```\n\n反观前端的测试代码基本上 2 种风格。前端的测试代码风格 1，它是最常用的测试方式，代码实例如下。\n\n```js\ntest(\"JSON\", () =\u003e {\n  const input = {\n    foo: \"hello\",\n    bar: \"world\",\n  };\n\n  const output = JSON.stringify(input);\n\n  assert.snapshot(output, `{\"foo\":\"hello\",\"bar\":\"world\"}`);\n  assert.equal(JSON.parse(output), input, \"matches original\");\n});\n```\n\n前端的测试代码风格 2，bdd 风格，它更强调行为对测试用例的影响，代码实例如下。\n\n```js\ndescribe(\"User\", function () {\n  describe(\"#save()\", function () {\n    it(\"should save without error\", function (done) {\n      var user = new User(\"Luna\");\n      user.save(function (err) {\n        if (err) throw err;\n        done();\n      });\n    });\n  });\n});\n```\n\n对比一下 Java 和 JavaScript 测试多个写法之后，你会发现，面向对象在 JavaScript（TypeScript）里根本不是一等公民。于是我就萌发了一个想法，想用 TypeScript 实现一下 JUnit。\n\n## 特性\n\n- ~~jest 支持 ts 需要引入 babel~~\n- ~~ts-jest 直接支持 ts，测试语法上是 jest 语法，suite/test 或 describe/it~~\n- ts-junit 支持 2 种用法，其中 cli 方式采用增量 ts 编译，效率很高的。\n- ts-junit 使用 junit 5 的装饰器进行封装，成熟，使用于熟悉 OO 的开发，尤其对了解 Java 的开发者更友好。\n- ts-junit 使用 uvu 作为默认策略，同时也可以实现各个常见测试框架的支持，比如 jest、mocha、ava、tape、qunit、jasmine 等（暂时未实现）。\n\n## 示例\n\n```ts\nimport assert from 'assert'\nimport { BeforeAll, BeforeEach, Disabled, Test, AfterEach, AfterAll } from 'ts-junit'\n\nexport default class MyFirstJUnitJupiterTests {\n    calculator = new Calculator()\n\n    @BeforeAll\n    static void initAll() {\n    }\n\n    @BeforeEach\n    void init() {\n    }\n\n    @Test\n    void succeedingTest() {\n\n    }\n\n    @Test\n    void failingTest() {\n        assert.fail(\"a failing test\");\n    }\n\n    @Test\n    @Disabled(\"for demonstration purposes\")\n    void skippedTest() {\n        // not executed\n    }\n\n    @Test\n    void abortedTest() {\n        assert.assumeTrue(\"abc\".contains(\"Z\"));\n        assert.fail(\"test should have been aborted\");\n    }\n\n    @AfterEach\n    void tearDown() {\n    }\n\n    @AfterAll\n    static void tearDownAll() {\n    }\n}\n```\n\n## Usages\n\n### 方式 1: 使用独立 cli 进行编译\n\n不依赖当前项目的 ts 环境，直接通过 cli 执行，参考源码中 tests 目录下的文件。\n\n```shell\n$ npm i --global @ts-junit/cli\n$ junit tests\n$ junit tests/test.ts\n```\n\n编写第一个测试用例\n\n```ts\nimport assert from 'assert'\nimport { Test } from '@ts-junit/core'\n\nexport default class MyFirstJUnitJupiterTests  {\n\n    calculator = new Calculator();\n\n    @Test\n    void addition() {\n        assert.is(2, calculator.add(1, 1));\n    }\n}\n```\n\n### 方式 2: 依赖当前项目的 ts 环境进行编译\n\n```shell\n$ npm i --save-dev @ts-junit/core\n```\n\n编写测试入口文件 ts-junit.ts，文件内指定测试文件或测试目录即可。\n\n```ts\nimport * as path from \"node:path\";\nimport { run } from \"@ts-junit/core\";\n\nconst folder = path.resolve(process.cwd(), \"./tests\");\nconst file = path.resolve(process.cwd(), \"./tests/test.ts\");\n\nrun([folder, file]);\n// or custom Strategy\n// import SomeStrategy from \"./SomeStrategy\";\n// run([folder, file], new SomeStrategy());\n```\n\n创建编译时的 tsconfig.json 文件\n\n```ts\n{\n  \"compileOnSave\": true,\n  \"compilerOptions\": {\n    \"target\": \"es2017\",\n    \"module\": \"commonjs\",\n    \"sourceMap\": true,\n    \"outDir\": \"./build\",\n    \"rootDir\": \"./src\",\n    \"typeRoots\": [],\n    \"types\": [],\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  },\n  \"exclude\": [\"node_modules\"],\n  \"include\": [\"./src/**/*.ts\", \"./test/**/*.ts\"]\n}\n```\n\n编辑 package.json 的启动和编译脚本\n\n```ts\n{\n  \"scripts\": {\n    \"test\": \"NODE_ENV=dev ts-node --project tsconfig.json --files ts-junit.ts\",\n    \"build\": \"tsc\"\n  }\n}\n```\n\n启动服务\n\n```\n$ npm test\n\u003e NODE_ENV=dev ts-node --project tsconfig.json --files ts-junit.ts\n[2020-9-1 19:52:12] [debug] [init] [router] get - /\n```\n\n## 装饰器\n\n- 参考 junit5 的文档 https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations\n- 进度 `7/20`\n\n\u003ctable class=\"tableblock frame-all grid-all stretch\"\u003e\n    \u003ccolgroup\u003e\n        \u003ccol style=\"width: 20%;\"\u003e\n        \u003ccol style=\"width: 80%;\"\u003e\n    \u003c/colgroup\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth class=\"tableblock halign-left valign-top\"\u003eAnnotation\u003c/th\u003e\n            \u003cth class=\"tableblock halign-left valign-top\"\u003eDescription\u003c/th\u003e\n            \u003cth class=\"tableblock halign-left valign-top\"\u003eisSupported\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@Test\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that a method is a test method. Unlike JUnit 4’s \u003ccode\u003e@Test\u003c/code\u003e\n                    annotation, this annotation does not declare any attributes, since test extensions in JUnit Jupiter\n                    operate based on their own dedicated annotations. Such methods are \u003cem\u003einherited\u003c/em\u003e unless they\n                    are \u003cem\u003eoverridden\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@ParameterizedTest\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that a method is a \u003ca\n                        href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests\"\u003eparameterized test\u003c/a\u003e. Such methods are\n                    \u003cem\u003einherited\u003c/em\u003e unless they are \u003cem\u003eoverridden\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@RepeatedTest\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that a method is a test template for a \u003ca\n                        href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-repeated-tests\"\u003erepeated test\u003c/a\u003e. Such methods are \u003cem\u003einherited\u003c/em\u003e\n                    unless they are \u003cem\u003eoverridden\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@TestFactory\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that a method is a test factory for \u003ca\n                        href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-dynamic-tests\"\u003edynamic tests\u003c/a\u003e. Such methods are \u003cem\u003einherited\u003c/em\u003e\n                    unless they are \u003cem\u003eoverridden\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@TestTemplate\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that a method is a \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-templates\"\u003etemplate for\n                        test cases\u003c/a\u003e designed to be invoked multiple times depending on the number of invocation\n                    contexts returned by the registered \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#extensions-test-templates\"\u003eproviders\u003c/a\u003e. Such methods\n                    are \u003cem\u003einherited\u003c/em\u003e unless they are \u003cem\u003eoverridden\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@TestMethodOrder\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to configure the \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order\"\u003etest method\n                        execution order\u003c/a\u003e for the annotated test class; similar to JUnit 4’s\n                    \u003ccode\u003e@FixMethodOrder\u003c/code\u003e. Such annotations are \u003cem\u003einherited\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@TestInstance\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to configure the \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-instance-lifecycle\"\u003etest\n                        instance lifecycle\u003c/a\u003e for the annotated test class. Such annotations are \u003cem\u003einherited\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@DisplayName\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDeclares a custom \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-display-names\"\u003edisplay name\u003c/a\u003e for the\n                    test class or test method. Such annotations are not \u003cem\u003einherited\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@DisplayNameGeneration\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDeclares a custom \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-display-name-generator\"\u003edisplay name\n                        generator\u003c/a\u003e for the test class. Such annotations are \u003cem\u003einherited\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@BeforeEach\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that the annotated method should be executed \u003cem\u003ebefore\u003c/em\u003e\n                    \u003cstrong\u003eeach\u003c/strong\u003e \u003ccode\u003e@Test\u003c/code\u003e, \u003ccode\u003e@RepeatedTest\u003c/code\u003e,\n                    \u003ccode\u003e@ParameterizedTest\u003c/code\u003e, or \u003ccode\u003e@TestFactory\u003c/code\u003e method in the current class; analogous\n                    to JUnit 4’s \u003ccode\u003e@Before\u003c/code\u003e. Such methods are \u003cem\u003einherited\u003c/em\u003e unless they are\n                    \u003cem\u003eoverridden\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@AfterEach\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that the annotated method should be executed \u003cem\u003eafter\u003c/em\u003e\n                    \u003cstrong\u003eeach\u003c/strong\u003e \u003ccode\u003e@Test\u003c/code\u003e, \u003ccode\u003e@RepeatedTest\u003c/code\u003e,\n                    \u003ccode\u003e@ParameterizedTest\u003c/code\u003e, or \u003ccode\u003e@TestFactory\u003c/code\u003e method in the current class; analogous\n                    to JUnit 4’s \u003ccode\u003e@After\u003c/code\u003e. Such methods are \u003cem\u003einherited\u003c/em\u003e unless they are\n                    \u003cem\u003eoverridden\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@BeforeAll\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that the annotated method should be executed \u003cem\u003ebefore\u003c/em\u003e\n                    \u003cstrong\u003eall\u003c/strong\u003e \u003ccode\u003e@Test\u003c/code\u003e, \u003ccode\u003e@RepeatedTest\u003c/code\u003e,\n                    \u003ccode\u003e@ParameterizedTest\u003c/code\u003e, and \u003ccode\u003e@TestFactory\u003c/code\u003e methods in the current class;\n                    analogous to JUnit 4’s \u003ccode\u003e@BeforeClass\u003c/code\u003e. Such methods are \u003cem\u003einherited\u003c/em\u003e (unless they\n                    are \u003cem\u003ehidden\u003c/em\u003e or \u003cem\u003eoverridden\u003c/em\u003e) and must be \u003ccode\u003estatic\u003c/code\u003e (unless the \"per-class\"\n                    \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-instance-lifecycle\"\u003etest instance lifecycle\u003c/a\u003e is used).\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@AfterAll\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that the annotated method should be executed \u003cem\u003eafter\u003c/em\u003e\n                    \u003cstrong\u003eall\u003c/strong\u003e \u003ccode\u003e@Test\u003c/code\u003e, \u003ccode\u003e@RepeatedTest\u003c/code\u003e,\n                    \u003ccode\u003e@ParameterizedTest\u003c/code\u003e, and \u003ccode\u003e@TestFactory\u003c/code\u003e methods in the current class;\n                    analogous to JUnit 4’s \u003ccode\u003e@AfterClass\u003c/code\u003e. Such methods are \u003cem\u003einherited\u003c/em\u003e (unless they\n                    are \u003cem\u003ehidden\u003c/em\u003e or \u003cem\u003eoverridden\u003c/em\u003e) and must be \u003ccode\u003estatic\u003c/code\u003e (unless the \"per-class\"\n                    \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-instance-lifecycle\"\u003etest instance lifecycle\u003c/a\u003e is used).\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@Nested\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eDenotes that the annotated class is a non-static \u003ca\n                        href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-nested\"\u003enested test class\u003c/a\u003e. \u003ccode\u003e@BeforeAll\u003c/code\u003e and\n                    \u003ccode\u003e@AfterAll\u003c/code\u003e methods cannot be used directly in a \u003ccode\u003e@Nested\u003c/code\u003e test class unless\n                    the \"per-class\" \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-instance-lifecycle\"\u003etest instance lifecycle\u003c/a\u003e is\n                    used. Such annotations are not \u003cem\u003einherited\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@Tag\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to declare \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-tagging-and-filtering\"\u003etags for filtering\n                        tests\u003c/a\u003e, either at the class or method level; analogous to test groups in TestNG or Categories\n                    in JUnit 4. Such annotations are \u003cem\u003einherited\u003c/em\u003e at the class level but not at the method level.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@Disabled\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-disabling\"\u003edisable\u003c/a\u003e a test class or test\n                    method; analogous to JUnit 4’s \u003ccode\u003e@Ignore\u003c/code\u003e. Such annotations are not \u003cem\u003einherited\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e✅\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@Timeout\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to fail a test, test factory, test template, or lifecycle method if its\n                    execution exceeds a given duration. Such annotations are \u003cem\u003einherited\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@ExtendWith\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#extensions-registration-declarative\"\u003eregister extensions\n                        declaratively\u003c/a\u003e. Such annotations are \u003cem\u003einherited\u003c/em\u003e.\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@RegisterExtension\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to \u003ca href=\"https://junit.org/junit5/docs/current/user-guide/#extensions-registration-programmatic\"\u003eregister extensions\n                        programmatically\u003c/a\u003e via fields. Such fields are \u003cem\u003einherited\u003c/em\u003e unless they are\n                    \u003cem\u003eshadowed\u003c/em\u003e.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003e\u003ccode\u003e@TempDir\u003c/code\u003e\u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e\n                \u003cp class=\"tableblock\"\u003eUsed to supply a \u003ca\n                        href=\"https://junit.org/junit5/docs/current/user-guide/#writing-tests-built-in-extensions-TempDirectory\"\u003etemporary directory\u003c/a\u003e via field\n                    injection or parameter injection in a lifecycle method or test method; located in the\n                    \u003ccode\u003eorg.junit.jupiter.api.io\u003c/code\u003e package.\n                \u003c/p\u003e\n            \u003c/td\u003e\n            \u003ctd class=\"tableblock halign-left valign-top\"\u003e❌\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\n## TODO\n\n1. 结合 https://github.com/midwayjs/injection 更简单(暂未实现)\n\n   ```ts\n   class Test {\n     @Inject()\n     helloTest: IHelloTest;\n     @Inject()\n     helloService: IHelloService;\n\n     @Before()\n     before() {\n       mock(helloTest, \"sayhello\", () =\u003e {\n         return \"mocked\";\n       });\n     }\n\n     @Test()\n     async test() {\n       expect(this.helloTest.sayhello()).eq(\"mocked\");\n\n       expect(this.helloService.sayhello(\"test\")).eq(\"hello test\");\n     }\n   }\n   ```\n\n2. use vm2 with require from memfs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi5ting%2Fts-junit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fi5ting%2Fts-junit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi5ting%2Fts-junit/lists"}