Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
/mockPublic

Mock library for egg testing.

License

NotificationsYou must be signed in to change notification settings

eggjs/mock

Repository files navigation

NPM versionNode.js CITest coveragenpm downloadNode.js VersionPRs Welcome

Mock library for testing Egg applications, plugins and custom Egg frameworks with ease.egg-mock inherits all APIs fromnode_modules/mm, offering more flexibility.

Install

npm i egg-mock --save-dev

Usage

Create testcase

Launch a mock server withmm.app

// test/index.test.jsconstpath=require('node:path');constmm=require('@eggjs/mock');describe('some test',()=>{letapp;before(()=>{app=mm.app({baseDir:'apps/foo'});returnapp.ready();})after(()=>app.close());it('should request /',()=>{returnapp.httpRequest().get('/').expect(200);});});

Retrieve Agent instance throughapp.agent aftermm.app started.

Usingmm.cluster launch cluster server, you can use the same API asmm.app;

Test Application

baseDir is optional that isprocess.cwd() by default.

before(()=>{app=mm.app();returnapp.ready();});

Test Framework

framework is optional, it'snode_modules/egg by default.

before(()=>{app=mm.app({baseDir:'apps/demo',framework:true,});returnapp.ready();});

Test Plugin

IfeggPlugin.name is defined inpackage.json, it's a plugin that will be loaded to plugin list automatically.

before(()=>{app=mm.app({baseDir:'apps/demo',});returnapp.ready();});

You can also test the plugin in different framework, e.g. testaliyun-egg and framework-b in one plugin.

describe('aliyun-egg',()=>{letapp;before(()=>{app=mm.app({baseDir:'apps/demo',framework:path.join(__dirname,'node_modules/aliyun-egg'),});returnapp.ready();});});describe('framework-b',()=>{letapp;before(()=>{app=mm.app({baseDir:'apps/demo',framework:path.join(__dirname,'node_modules/framework-b'),});returnapp.ready();});});

If it's detected as an plugin, but you don't want it to be, you can useplugin = false.

before(()=>{app=mm.app({baseDir:'apps/demo',plugin:false,});returnapp.ready();});

API

mm.app(options)

Create a mock application.

mm.cluster(options)

Create a mock cluster server, but you can't use API in application, you should test usingsupertest.

constmm=require('@eggjs/mock');describe('test/app.js',()=>{letapp,config;before(()=>{app=mm.cluster();returnapp.ready();});after(()=>app.close());it('some test',()=>{returnapp.httpRequest().get('/config').expect(200)});});

You can disable coverage, because it's slow.

mm.cluster({coverage:false,});

mm.env(env)

Mock env when starting

// production environmentmm.env('prod');mm.app({cache:false,});

Environment listhttps://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L82

mm.consoleLevel(level)

Mock level that print to stdout/stderr

// DON'T log to terminalmm.consoleLevel('NONE');

level list:DEBUG,INFO,WARN,ERROR,NONE

mm.home(homePath)

mock home directory

mm.restore()

restore all mock data, e.g.afterEach(mm.restore)

options

Options formm.app andmm.cluster

baseDir {String}

The directory of application, default isprocess.cwd().

mm.app({baseDir:path.join(__dirname,'fixtures/apps/demo'),})

You can use a string based on$CWD/test/fixtures for short

mm.app({baseDir:'apps/demo',})

framework {String/Boolean}

The directory of framework

mm.app({baseDir:'apps/demo',framework:path.join(__dirname,'fixtures/egg'),})

It can be true when test an framework

plugin

The directory of plugin, it's detected automatically.

mm.app({baseDir:'apps/demo',})

plugins {Object}

Define a list of plugins

cache {Boolean}

Determine whether enable cache. it's cached by baseDir.

clean {Boolean}

Clean all logs directory, default is true.

If you are usingava, disable it.

app.mockLog([logger]) and app.expectLog(str[, logger]), app.notExpectLog(str[, logger])

Assert some string value in the logger instance.It is recommended to pairapp.mockLog() withapp.expectLog() orapp.notExpectLog().Usingapp.expectLog() orapp.notExpectLog() alone requires dependency on the write speed of the log. When the server disk is high IO, unstable results will occur.

it('should work',async()=>{app.mockLog();awaitapp.httpRequest().get('/').expect('hello world').expect(200);app.expectLog('foo in logger');app.expectLog('foo in coreLogger','coreLogger');app.expectLog('foo in myCustomLogger','myCustomLogger');app.notExpectLog('bar in logger');app.notExpectLog('bar in coreLogger','coreLogger');app.notExpectLog('bar in myCustomLogger','myCustomLogger');});

app.httpRequest()

Request current app http server.

it('should work',()=>{returnapp.httpRequest().get('/').expect('hello world').expect(200);});

Seesupertest to get more APIs.

.unexpectHeader(name)

Assert current response not contains the specified header

it('should work',()=>{returnapp.httpRequest().get('/').unexpectHeader('set-cookie').expect(200);});

.expectHeader(name)

Assert current response contains the specified header

it('should work',()=>{returnapp.httpRequest().get('/').expectHeader('set-cookie').expect(200);});

app.mockContext(options)

constctx=app.mockContext({user:{name:'Jason'}});console.log(ctx.user.name);// Jason

app.mockContextScope(fn, options)

awaitapp.mockContextScope(asyncctx=>{console.log(ctx.user.name);// Jason},{user:{name:'Jason'}});

app.mockCookies(data)

app.mockCookies({foo:'bar'});constctx=app.mockContext();console.log(ctx.getCookie('foo'));

app.mockHeaders(data)

Mock request header

app.mockSession(data)

app.mockSession({foo:'bar'});constctx=app.mockContext();console.log(ctx.session.foo);

app.mockService(service, methodName, fn)

it('should mock user name',asyncfunction(){app.mockService('user','getName',asyncfunction(ctx,methodName,args){return'popomore';});constctx=app.mockContext();awaitctx.service.user.getName();});

app.mockServiceError(service, methodName, error)

You can mock an error for service

app.mockServiceError('user','home',newError('mock error'));

app.mockCsrf()

app.mockCsrf();returnapp.httpRequest().post('/login').expect(302);

app.mockHttpclient(url, method, data)

Mock httpclient request, e.g.:ctx.curl

app.get('/',asyncfunction(){constret=awaitthis.curl('https://eggjs.org');this.body=ret.data.toString();});app.mockHttpclient('https://eggjs.org',{// can be buffer / string / json / function// will auto convert to buffer// follow options.dataType to convertdata:'mock egg',});// app.mockHttpclient('https://eggjs.org', 'get', mockResponse); // mock get// app.mockHttpclient('https://eggjs.org', [ 'get' , 'head' ], mockResponse); // mock get and head// app.mockHttpclient('https://eggjs.org', '*', mockResponse); // mock all methods// app.mockHttpclient('https://eggjs.org', mockResponse); // mock all methods by default// app.mockHttpclient('https://eggjs.org', 'get', function(url, opt) { return 'xxx' }); // support fnreturnapp.httpRequest().post('/').expect('mock egg');

You can also use Regular Expression for matching url.

app.mockHttpclient(/\/users\/[a-z]$/i,{data:{name:'egg',},});

You can alse mock agent.httpclient

app.agent.mockHttpclient('https://eggjs.org',{data:{name:'egg',},});

Bootstrap

We also provide a bootstrap file for applications' unit test to reduce duplicated code:

const{ app, mock, assert}=require('@eggjs/mock/bootstrap');describe('test app',()=>{it('should request success',()=>{// mock data will be restored each casemock.data(app,'method',{foo:'bar'});returnapp.httpRequest().get('/foo').expect(res=>{assert(!res.headers.foo);}).expect(/bar/);});});describe('test ctx',()=>{it('can use ctx',asyncfunction(){constres=awaitthis.ctx.service.foo();assert(res==='foo');});});

We inject ctx to every test case, so you can useapp.currentContext in your test case.and the first call ofapp.mockContext will reuseapp.currentContext.

const{ app, mock, assert}=require('@eggjs/mock/bootstrap');describe('test ctx',()=>{it('should can use ctx',()=>{constctx=app.currentContext;assert(ctx);});it('should reuse ctx',()=>{constctx=app.currentContext;// first call will reuse app.currentContextconstmockCtx=app.mockContext();assert(ctx===mockCtx);// next call will create a new context// multi call app.mockContext will get wrong context with app.currentContext// so we recommend to use app.mockContextScopeconstmockCtx2=app.mockContext();assert(ctx!==mockCtx);});});

And if you use mm.app to bootstrap app, you can manually call setGetAppCallback,then egg-mock will inject ctx for each test case.

// test/.setup.jsconstmm=require('@eggjs/mock');constpath=require('path');before(asyncfunction(){constapp=this.app=mm.app();mm.setGetAppCallback(()=>{returnapp;});awaitapp.ready();});// test/index.test.jsit('should work',function(){// eslint-disable-next-line no-undefassert(this.app.currentContext);});

env for custom bootstrap

EGG_BASE_DIR: the base dir of egg appEGG_FRAMEWORK: the framework of egg app

Questions & Suggestions

Please open an issuehere.

License

MIT

Contributors

Contributors

Made withcontributors-img.


[8]ページ先頭

©2009-2025 Movatter.jp