From de2ce91fe7746c8276560c6fb12aa591fcc95f14 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Fri, 8 Nov 2024 22:43:58 +0800 Subject: [PATCH] feat: add grouping for mock data (#4151) * feat: add grouping for mock data * docs: update api --- packages/core/src/service/mockService.ts | 143 +++++++++++++----- .../core/test/service/mockService.test.ts | 128 +++++++++++++++- packages/mock/src/mock.ts | 66 +++++--- site/docs/built_in_service.md | 44 +++--- site/docs/mock.md | 42 +++++ .../current/built_in_service.md | 60 ++++---- .../current/mock.md | 47 +++++- 7 files changed, 413 insertions(+), 117 deletions(-) diff --git a/packages/core/src/service/mockService.ts b/packages/core/src/service/mockService.ts index aefcb5ac257a..0464830bbf52 100644 --- a/packages/core/src/service/mockService.ts +++ b/packages/core/src/service/mockService.ts @@ -13,17 +13,35 @@ import { Scope, MOCK_KEY, } from '../decorator'; +import { isClass } from '../util/types'; @Provide() @Scope(ScopeEnum.Singleton) export class MidwayMockService { - protected mocks = []; - protected contextMocks: Array<{ - app: IMidwayApplication; - key: string | ((ctx: IMidwayContext) => void); - value: any; - }> = []; - protected cache = new Map(); + /** + * Save class prototype and object property mocks + */ + protected mocks: Map< + string, + Array<{ + obj: any; + key: string; + descriptor: PropertyDescriptor; + hasOwnProperty: boolean; + }> + > = new Map(); + /** + * Save context mocks + */ + protected contextMocks: Map< + string, + Array<{ + app: IMidwayApplication; + key: string | ((ctx: IMidwayContext) => void); + value: any; + }> + > = new Map(); + protected cache: Map>> = new Map(); protected simulatorList: Array = []; constructor(readonly applicationContext: IMidwayContainer) {} @@ -31,59 +49,80 @@ export class MidwayMockService { async init() { if (MidwayMockService.prepareMocks.length > 0) { for (const item of MidwayMockService.prepareMocks) { - this.mockProperty(item.obj, item.key, item.value); + this.mockProperty(item.obj, item.key, item.value, item.group); } MidwayMockService.prepareMocks = []; } } + /** + * Prepare mocks before the service is initialized + */ static prepareMocks = []; static mockClassProperty( clzz: new (...args) => any, propertyName: string, - value: any + value: any, + group = 'default' ) { - this.mockProperty(clzz.prototype, propertyName, value); + this.mockProperty(clzz.prototype, propertyName, value, group); } - static mockProperty(obj: new (...args) => any, key: string, value: any) { + static mockProperty( + obj: new (...args) => any, + key: string, + value: any, + group = 'default' + ) { this.prepareMocks.push({ obj, key, value, + group, }); } public mockClassProperty( clzz: new (...args) => any, propertyName: string, - value: any + value: any, + group = 'default' ) { - return this.mockProperty(clzz.prototype, propertyName, value); + return this.mockProperty(clzz.prototype, propertyName, value, group); } - public mockProperty(obj: any, key: string, value) { + public mockProperty(obj: any, key: string, value: any, group = 'default') { // eslint-disable-next-line no-prototype-builtins const hasOwnProperty = obj.hasOwnProperty(key); - this.mocks.push({ + const mockItem = { obj, key, descriptor: Object.getOwnPropertyDescriptor(obj, key), // Make sure the key exists on object not the prototype hasOwnProperty, - }); + }; + + if (!this.mocks.has(group)) { + this.mocks.set(group, []); + } + this.mocks.get(group).push(mockItem); - // Delete the origin key, redefine it below if (hasOwnProperty) { delete obj[key]; } // Set a flag that checks if it is mocked - let flag = this.cache.get(obj); + let groupCache = this.cache.get(group); + if (!groupCache) { + groupCache = new Map(); + this.cache.set(group, groupCache); + } + + let flag = groupCache.get(obj); if (!flag) { flag = new Set(); - this.cache.set(obj, flag); + groupCache.set(obj, flag); } flag.add(key); @@ -94,42 +133,68 @@ export class MidwayMockService { public mockContext( app: IMidwayApplication, key: string | ((ctx: IMidwayContext) => void), - value?: PropertyDescriptor | any + value?: PropertyDescriptor | any, + group = 'default' ) { - this.contextMocks.push({ + if (!this.contextMocks.has(group)) { + this.contextMocks.set(group, []); + } + this.contextMocks.get(group).push({ app, key, value, }); } + public restore(group = 'default') { + this.restoreGroup(group); + } + @Destroy() - restore() { - for (let i = this.mocks.length - 1; i >= 0; i--) { - const m = this.mocks[i]; + public restoreAll() { + const groups = new Set([ + ...this.mocks.keys(), + ...this.contextMocks.keys(), + ...this.cache.keys(), + ]); + + for (const group of groups) { + this.restoreGroup(group); + } + + this.simulatorList = []; + } + + private restoreGroup(group: string) { + const groupMocks = this.mocks.get(group) || []; + for (let i = groupMocks.length - 1; i >= 0; i--) { + const m = groupMocks[i]; if (!m.hasOwnProperty) { - // Delete the mock key, use key on the prototype delete m.obj[m.key]; } else { - // Redefine the origin key instead of the mock key Object.defineProperty(m.obj, m.key, m.descriptor); } } - this.mocks = []; - this.contextMocks = []; - this.cache.clear(); - this.simulatorList = []; - MidwayMockService.prepareMocks = []; + this.mocks.delete(group); + this.contextMocks.delete(group); + this.cache.delete(group); + this.simulatorList = this.simulatorList.filter( + sim => sim['group'] !== group + ); } - isMocked(obj, key) { - const flag = this.cache.get(obj); + public isMocked(obj, key, group = 'default') { + if (isClass(obj)) { + obj = obj.prototype; + } + const groupCache = this.cache.get(group); + const flag = groupCache ? groupCache.get(obj) : undefined; return flag ? flag.has(key) : false; } applyContextMocks(app: IMidwayApplication, ctx: IMidwayContext) { - if (this.contextMocks.length > 0) { - for (const mockItem of this.contextMocks) { + for (const [, groupMocks] of this.contextMocks) { + for (const mockItem of groupMocks) { if (mockItem.app === app) { const descriptor = this.overridePropertyDescriptor(mockItem.value); if (typeof mockItem.key === 'string') { @@ -143,7 +208,10 @@ export class MidwayMockService { } getContextMocksSize() { - return this.contextMocks.length; + return Array.from(this.contextMocks.values()).reduce( + (sum, group) => sum + group.length, + 0 + ); } private overridePropertyDescriptor(value) { @@ -165,13 +233,14 @@ export class MidwayMockService { return descriptor; } - public async initSimulation() { + public async initSimulation(group = 'default') { const simulationModule: Array ISimulation> = listModule(MOCK_KEY); for (const module of simulationModule) { const instance = await this.applicationContext.getAsync(module); if (await instance.enableCondition()) { + instance['group'] = group; this.simulatorList.push(instance); } } diff --git a/packages/core/test/service/mockService.test.ts b/packages/core/test/service/mockService.test.ts index b99c26a00de3..556d0bce5856 100644 --- a/packages/core/test/service/mockService.test.ts +++ b/packages/core/test/service/mockService.test.ts @@ -4,15 +4,24 @@ import { MidwayMockService, IMidwayApplication } from '../../src'; import { UserService } from '../fixtures/base-app-ctx-mock/src/configuration'; describe('/service/mockService.test.ts', () => { + let framework; + let app: IMidwayApplication; + let mockService: MidwayMockService; - it('should test mock context', async () => { - const framework = await createLightFramework(path.join( + beforeAll(async () => { + framework = await createLightFramework(path.join( __dirname, './fixtures/base-app-ctx-mock/src' )); + app = framework.getApplication() as IMidwayApplication; + mockService = framework.getApplicationContext().get(MidwayMockService); + }); - const app = framework.getApplication() as IMidwayApplication; - const mockService = framework.getApplicationContext().get(MidwayMockService); + afterAll(async () => { + await framework.stop(); + }); + + it('should test mock context', async () => { mockService.mockContext(app, 'user', 'zhangting'); mockService.mockContext(app, (ctx) => { ctx['bbbb'] = 'cccc'; @@ -62,7 +71,116 @@ describe('/service/mockService.test.ts', () => { mockService.restore(); expect(await userService.invoke()).toEqual('hello world'); + }); - await framework.stop(); + it('should test mock with groups', async () => { + // 测试不同分组的 mock + mockService.mockContext(app, 'user', 'zhangting', 'group1'); + mockService.mockContext(app, 'role', 'admin', 'group2'); + + let ctx = app.createAnonymousContext(); + const fn = await framework.applyMiddleware(); + await fn((ctx)); + + expect(ctx['user']).toEqual('zhangting'); + expect(ctx['role']).toEqual('admin'); + + // 测试恢复单个分组 + mockService.restore('group1'); + + ctx = app.createAnonymousContext(); + await (await framework.applyMiddleware())(ctx); + + expect(ctx['user']).toBeUndefined(); + expect(ctx['role']).toEqual('admin'); + + // 测试恢复所有分组 + mockService.restoreAll(); + + ctx = app.createAnonymousContext(); + await (await framework.applyMiddleware())(ctx); + + expect(ctx['user']).toBeUndefined(); + expect(ctx['role']).toBeUndefined(); + }); + + it('should test mock class property with groups', async () => { + framework.getApplicationContext().bindClass(UserService); + mockService.mockClassProperty(UserService, 'invoke', () => '1112', 'group1'); + mockService.mockClassProperty(UserService, 'getName', () => 'mockName', 'group2'); + + expect(mockService.isMocked(UserService, 'invoke', 'group1')).toBeTruthy(); + + const userService = await framework.getApplicationContext().getAsync(UserService); + expect(userService.invoke()).toEqual('1112'); + expect(userService.getName()).toEqual('mockName'); + + // 恢复单个分组 + mockService.restore('group1'); + + expect(await userService.invoke()).toEqual('hello world'); + expect(userService.getName()).toEqual('mockName'); + + // 恢复所有分组 + mockService.restoreAll(); + + expect(mockService.isMocked(UserService, 'invoke', 'group1')).toBeFalsy(); + expect(await userService.invoke()).toEqual('hello world'); + expect(() => { + userService.getName(); + }).toThrow('userService.getName is not a function'); + }); + + it('should test mock property with groups', async () => { + const obj = { + method1: () => 'original1', + method2: () => 'original2' + }; + + mockService.mockProperty(obj, 'method1', () => 'mocked1', 'group1'); + mockService.mockProperty(obj, 'method2', () => 'mocked2', 'group2'); + + expect(obj.method1()).toEqual('mocked1'); + expect(obj.method2()).toEqual('mocked2'); + + // 恢复单个分组 + mockService.restore('group1'); + + expect(obj.method1()).toEqual('original1'); + expect(obj.method2()).toEqual('mocked2'); + + // 恢复所有分组 + mockService.restoreAll(); + + expect(obj.method1()).toEqual('original1'); + expect(obj.method2()).toEqual('original2'); + }); + + it('should test isMocked with groups', async () => { + const obj = { method: () => 'original' }; + + mockService.mockProperty(obj, 'method', () => 'mocked', 'testGroup'); + + expect(mockService.isMocked(obj, 'method', 'testGroup')).toBeTruthy(); + + mockService.restore('testGroup'); + + expect(mockService.isMocked(obj, 'method', 'testGroup')).toBeFalsy(); + }); + + it('should test mock without specifying group', async () => { + const obj = { method: () => 'original' }; + + // 不传 group,使用默认分组 + mockService.mockProperty(obj, 'method', () => 'mocked'); + + expect(mockService.isMocked(obj, 'method')).toBeTruthy(); + expect(obj.method()).toEqual('mocked'); + + // 恢复默认分组 + mockService.restore(); + + expect(mockService.isMocked(obj, 'method')).toBeFalsy(); + expect(obj.method()).toEqual('original'); }); }); diff --git a/packages/mock/src/mock.ts b/packages/mock/src/mock.ts index f6101079d61f..ec3c1daa42f6 100644 --- a/packages/mock/src/mock.ts +++ b/packages/mock/src/mock.ts @@ -27,64 +27,90 @@ function getMockService(app?): MidwayMockService { export function mockSession( app: IMidwayApplication, key: string, - value: any + value: any, + group = 'default' ) { const mockService = getMockService(app); - mockService.mockContext(app, (ctx: any) => { - if (!ctx.session) { - ctx.session = {}; - } - ctx.session[key] = value; - }); + mockService.mockContext( + app, + (ctx: any) => { + if (!ctx.session) { + ctx.session = {}; + } + ctx.session[key] = value; + }, + undefined, + group + ); } export function mockHeader( app: IMidwayApplication, headerKey: string, - headerValue: string + headerValue: string, + group = 'default' ) { const mockService = getMockService(app); - mockService.mockContext(app, (ctx: any) => { - ctx.headers[headerKey] = headerValue; - }); + mockService.mockContext( + app, + (ctx: any) => { + ctx.headers[headerKey] = headerValue; + }, + undefined, + group + ); } export function mockClassProperty( clzz: new (...args) => any, propertyName: string, - value: any + value: any, + group = 'default' ) { const mockService = getMockService(); if (!mockService) { - return MidwayMockService.mockClassProperty(clzz, propertyName, value); + return MidwayMockService.mockClassProperty( + clzz, + propertyName, + value, + group + ); } else { - return mockService.mockClassProperty(clzz, propertyName, value); + return mockService.mockClassProperty(clzz, propertyName, value, group); } } -export function mockProperty(obj: any, key: string, value) { +export function mockProperty(obj: any, key: string, value, group = 'default') { const mockService = getMockService(); if (!mockService) { - return MidwayMockService.mockProperty(obj, key, value); + return MidwayMockService.mockProperty(obj, key, value, group); } else { - return mockService.mockProperty(obj, key, value); + return mockService.mockProperty(obj, key, value, group); } } export function restoreAllMocks() { const mockService = getMockService(); if (mockService) { - mockService.restore(); + mockService.restoreAll(); } else { MidwayMockService.prepareMocks = []; } } +export function restoreMocks(group = 'default') { + const mockService = getMockService(); + if (mockService) { + mockService.restore(group); + } +} + export function mockContext( app: IMidwayApplication, key: string | ((ctx: IMidwayContext) => void), - value?: PropertyDescriptor | any + value?: PropertyDescriptor | any, + group = 'default' ) { const mockService = getMockService(app); - mockService.mockContext(app, key, value); + mockService.mockContext(app, key, value, group); } diff --git a/site/docs/built_in_service.md b/site/docs/built_in_service.md index 082f24a58d6e..393e95aaa7ee 100644 --- a/site/docs/built_in_service.md +++ b/site/docs/built_in_service.md @@ -113,7 +113,7 @@ export class HomeController { ## MidwayConfigService -Midway 内置的多环境配置服务,提供配置的加载,获取,它也是 `@Config` 装饰器的数据源。 +Midway 内置的多环境配置服务,提供配置的加载,获取它也是 `@Config` 装饰器的数据源。 可以通过注入获取。 @@ -337,17 +337,15 @@ API 如下 | API | 返回类型 | 描述 | | -------------------------------------------- | -------- | ---------------------------------- | -| mockClassProperty(clzz, propertyName, value) | | mock 一个class 上的属性(方法 ) | -| mockProperty(obj, key, value) | | mock 一个普通对象上的属性(方法 ) | -| mockContext(app, key, vlue) | | mock 上下文对象上的属性 | -| restore() | | 清空所有 mock 数据 | - +| mockClassProperty(clzz, propertyName, value, group?) | | mock 一个 class 上的属性(方法),支持分组,默认分组为 `default` | +| mockProperty(obj, key, value, group?) | | mock 一个普通对象上的属性(方法),支持分组,默认分组为 `default` | +| mockContext(app, key, value, group?) | | mock 上下文对象上的属性,支持分组,默认分组为 `default` | +| restore(group?) | | 恢复指定分组的 mock 数据,未指定则恢复所有 | +| restoreAll() | | 清空所有 mock 数据 | ### mockClassProperty -用于模拟类的某个属性或者方法。 - -比如某个类。 +用于模拟类的某个属性或者方法。支持通过 `group` 参数指定分组。如果不传 `group` 参数,默认使用 `default` 分组。 ```typescript @Provide() @@ -372,15 +370,15 @@ class TestMockService { mockService: MidwayMockService; mock() { - // 模拟方法 + // 模拟属性,使用默认分组 this.mockService.mockClassProperty(UserService, 'getUser', async () => { return 'midway'; }); - // 模拟属性 + // 模拟属性,指定分组 this.mockService.mockClassProperty(UserService, 'data', { bbb: '1' - }); + }, 'group2'); } } ``` @@ -389,7 +387,7 @@ class TestMockService { ### mockProperty -使用 `mockProperty` 方法来模拟对象的属性。 +使用 `mockProperty` 方法来模拟对象的属性。支持通过 `group` 参数指定分组。 ```typescript import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @@ -401,14 +399,16 @@ class TestMockService { mock() { const a = {}; - // 模拟属性 + // 默认分组 this.mockService.mockProperty(a, 'name', 'hello'); + // 模拟属性,自定义分组 + this.mockService.mockProperty(a, 'name', 'hello', 'group1'); // a['name'] => 'hello' // 模拟方法 this.mockService.mockProperty(a, 'getUser', async () => { return 'midway'; - }); + }, 'group2'); // await a.getUser() => 'midway' } } @@ -419,7 +419,7 @@ class TestMockService { ### mockContext -由于 Midway 的 Context 和 app 关联,所以在模拟的时候需要传入 app 实例。 +由于 Midway 的 Context 和 app 关联,所以在模拟的时候需要传入 app 实例。支持通过 `group` 参数指定分组。 使用 `mockContext` 方法来模拟上下文。 @@ -435,8 +435,10 @@ export class MainConfiguration { app; async onReady() { - // 模拟上下文 - mockContext(app, 'user', 'midway'); + // 模拟上下文, 默认分组 + this.mockService.mockContext(app, 'user', 'midway'); + // 自定义分组 + this.mockService.mockContext(app, 'user', 'midway', 'group1'); } } @@ -458,9 +460,9 @@ export class MainConfiguration { async onReady() { // 模拟上下文 - mockContext(app, (ctx) => { + this.mockService.mockContext(app, (ctx) => { ctx.user = 'midway'; - }); + }, 'group2'); } } @@ -639,3 +641,5 @@ export default { ``` 健康检查的执行端在业务或者组件的生命周期中实现,具体请查看 [生命周期](/docs/lifecycle#onhealthcheck)。 + + diff --git a/site/docs/mock.md b/site/docs/mock.md index 1e76b3cf9578..df4f4726231b 100644 --- a/site/docs/mock.md +++ b/site/docs/mock.md @@ -170,6 +170,37 @@ it('should test create koa app with new mode with mock', async () => { }); ``` +### 分组 + +从 `3.19.0` 开始,Midway 的 mock 功能支持通过分组来管理不同的 mock 数据。你可以在创建 mock 时指定一个分组名称,这样可以在需要时单独恢复或清理某个分组的 mock 数据。 + + +```typescript +import { mockContext, restoreMocks } from '@midwayjs/mock'; + +it('should test mock with groups', async () => { + const app = await createApp(); + + // 创建普通对象的 mock + const a = {}; + mockProperty(a, 'getUser', async () => { + return 'midway'; + }, 'group1'); + + // 创建上下文的 mock + mockContext(app, 'user', 'midway', 'group1'); + mockContext(app, 'role', 'admin', 'group2'); + + // 恢复单个分组 + restoreMocks('group1'); + + // 恢复所有分组 + restoreAllMocks(); +}); +``` + +通过分组,你可以更灵活地管理和控制 mock 数据,特别是在复杂的测试场景中。 + ### 清理 mock @@ -187,6 +218,16 @@ it('should test create koa app with new mode with mock', async () => { }); ``` +从 `3.19.0` 开始,支持指定 group 清理。 + +```typescript +import { restoreMocks } from '@midwayjs/mock'; + +it('should test create koa app with new mode with mock', async () => { + restoreMocks('group1');(); + // ... +}); +``` ## 标准 Mock 服务 @@ -388,3 +429,4 @@ export class InitDataMock implements ISimulation { } ``` + diff --git a/site/i18n/en/docusaurus-plugin-content-docs/current/built_in_service.md b/site/i18n/en/docusaurus-plugin-content-docs/current/built_in_service.md index 8d9394c6b212..a067325430ef 100644 --- a/site/i18n/en/docusaurus-plugin-content-docs/current/built_in_service.md +++ b/site/i18n/en/docusaurus-plugin-content-docs/current/built_in_service.md @@ -312,7 +312,7 @@ This service is an internal method and cannot be used directly by users. ## MidwayMockService -Midway's built-in data simulation service is used to simulate data during development and single test. +Midway's built-in data simulation service is used to simulate data during development and testing. It can be obtained by injection. @@ -327,26 +327,24 @@ export class HomeController { @Get('/') async home() { - // this.mockService.mockProperty(/** 省略 **/); + // this.mockService.mockProperty(/** omitted **/); } } ``` API is as follows -| API | Return type | Description | -| -------------------------------------------- | -------- | ---------------------------------- | -| mockClassProperty(clzz, propertyName, value) | | Mock a property on a class (method) | -| mockProperty(obj, key, value) | | Mock a property (method) on a normal object | -| mockContext(app, key, vlue) | | Properties on mock Context Objects | -| restore() | | Empty all mock data | - +| API | Return type | Description | +| -------------------------------------------- | ----------- | ----------------------------------------- | +| mockClassProperty(clzz, propertyName, value, group?) | | Mock a property (method) on a class, supports grouping, default group is `default` | +| mockProperty(obj, key, value, group?) | | Mock a property (method) on a normal object, supports grouping, default group is `default` | +| mockContext(app, key, value, group?) | | Mock properties on context objects, supports grouping, default group is `default` | +| restore(group?) | | Restore mock data for the specified group, restore all if not specified | +| restoreAll() | | Clear all mock data | ### mockClassProperty -Used to simulate a property or method of a class. - -Like a class. +Used to simulate a property or method of a class. Supports specifying a group through the `group` parameter. If the `group` parameter is not passed, the default group `default` is used. ```typescript @Provide() @@ -362,7 +360,6 @@ export class UserService { We can also simulate in code. ```typescript - import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @Provide() @@ -371,24 +368,22 @@ class TestMockService { mockService: MidwayMockService; mock() { - // Simulation method + // Simulate property, use default group this.mockService.mockClassProperty(UserService, 'getUser', async () => { return 'midway'; }); - // Simulation properties + // Simulate property, specify group this.mockService.mockClassProperty(UserService, 'data', { bbb: '1' - }); + }, 'group2'); } } ``` - - ### mockProperty -Use `mockProperty` methods to simulate the properties of objects. +Use the `mockProperty` method to simulate the properties of objects. Supports specifying a group through the `group` parameter. ```typescript import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @@ -400,27 +395,26 @@ class TestMockService { mock() { const a = {}; - // Simulation properties + // Default group this.mockService.mockProperty(a, 'name', 'hello'); + // Simulate property, custom group + this.mockService.mockProperty(a, 'name', 'hello', 'group1'); // a['name'] => 'hello' - // Simulation method + // Simulate method this.mockService.mockProperty(a, 'getUser', async () => { return 'midway'; - }); + }, 'group2'); // await a.getUser() => 'midway' } } - ``` - - ### mockContext -Since Midway's Context is associated with app, app instances need to be passed in during simulation. +Since Midway's Context is associated with app, app instances need to be passed in during simulation. Supports specifying a group through the `group` parameter. -`mockContext` methods are used to simulate the context. +Use the `mockContext` method to simulate the context. ```typescript import { MidwayMockService, Configuration, App } from '@midwayjs/core'; @@ -434,8 +428,10 @@ export class MainConfiguration { app; async onReady() { - // Simulation context - mockContext(app, 'user', 'midway'); + // Simulate context, default group + this.mockService.mockContext(app, 'user', 'midway'); + // Custom group + this.mockService.mockContext(app, 'user', 'midway', 'group1'); } } @@ -456,10 +452,10 @@ export class MainConfiguration { app; async onReady() { - // Simulation context - mockContext(app, (ctx) => { + // Simulate context + this.mockService.mockContext(app, (ctx) => { ctx.user = 'midway'; - }); + }, 'group2'); } } diff --git a/site/i18n/en/docusaurus-plugin-content-docs/current/mock.md b/site/i18n/en/docusaurus-plugin-content-docs/current/mock.md index 0f93ca100157..16fd967c488c 100644 --- a/site/i18n/en/docusaurus-plugin-content-docs/current/mock.md +++ b/site/i18n/en/docusaurus-plugin-content-docs/current/mock.md @@ -172,11 +172,43 @@ it('should test create koa app with new mode with mock', async () => { -### Clean up mock +### Grouping + +Starting from version `3.19.0`, Midway's mock functionality supports managing different mock data through grouping. You can specify a group name when creating a mock, allowing you to restore or clean up a specific group of mock data as needed. + +```typescript +import { mockContext, restoreMocks } from '@midwayjs/mock'; + +it('should test mock with groups', async () => { + const app = await createApp(); + + // Create a mock for a regular object + const a = {}; + mockProperty(a, 'getUser', async () => { + return 'midway'; + }, 'group1'); + + // Create a mock for the context + mockContext(app, 'user', 'midway', 'group1'); + mockContext(app, 'role', 'admin', 'group2'); + + // Restore a single group + restoreMocks('group1'); + + // Restore all groups + restoreAllMocks(); +}); +``` + +By using groups, you can manage and control mock data more flexibly, especially in complex testing scenarios. + + + +### Cleaning up mocks Every time the `close` method is called, all mock data is automatically cleared. -If you want to clean up manually, you can also perform method `restoreAllMocks`. +If you want to clean up manually, you can also execute the `restoreAllMocks` method. ```typescript import { restoreAllMocks } from '@midwayjs/mock'; @@ -187,9 +219,18 @@ it('should test create koa app with new mode with mock', async () => { }); ``` +Starting from version `3.19.0`, it supports cleaning up by specifying a group. +```typescript +import { restoreMocks } from '@midwayjs/mock'; + +it('should test create koa app with new mode with mock', async () => { + restoreMocks('group1'); + // ... +}); +``` -## Standard Mock service +### Standard Mock service Midway provides standard MidwayMockService services for simulating data in code.