Ionic单元测试前期配置

作者: Gary嘉骏 | 来源:发表于2017-09-09 23:07 被阅读0次

一、安装依赖:

  1. npm i webpack -g

  2. npm i karma-cli -g

  3. npm i @ionic/cli-build-ionic-angular @ionic/cli-plugin-cordova @types/jasmine@2.5.36 @types/node angular2-template-loader html-loader istanbul-instrumenter-loader jasmine jasmine-spec-reporter karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter karma-sourcemap-loader karma-webpack null-loader protractor ts-loader ts-node --save-dev

  4. 安装谷歌浏览器(测试报告会自动打开谷歌浏览器显示)

二、配置文件

1. 在 src内新建mocks.ts,内容如下:

/* tslint:disable */
// IONIC:
import { EventEmitter}      from '@angular/core';
import { FormBuilder }      from '@angular/forms';

export class AlertMock {

  public create(): any {
    let rtn: Object = {};
    rtn['present'] = (() => true);
    return rtn;
  }

  // function actually on the AlertClass (not AlertController), but using these interchangably for now
  public dismiss(): Promise<{}> {
    return new Promise(function(resolve: Function): void {
      resolve();
    });
  }
}

export class ToastMock {

  public create(): any {
    let rtn: Object = {};
    rtn['present'] = (() => true);
    return rtn;
  }
}

export class ConfigMock {

  public get(): any {
    return '';
  }

  public getBoolean(): boolean {
    return true;
  }

  public getNumber(): number {
    return 1;
  }

  public setTransition(): void {
    return;
  }
}

export class FormMock {
  public register(): any {
    return true;
  }
}

export class NavMock {

  public pop(): any {
    return new Promise(function(resolve: Function): void {
      resolve();
    });
  }

  public push(): any {
    return new Promise(function(resolve: Function): void {
      resolve();
    });
  }

  public getActive(): any {
    return {
      'instance': {
        'model': 'something',
      },
    };
  }

  public setRoot(): any {
    return true;
  }

  public popToRoot(): any {
    return true;
  }
}

export class PlatformMock {
  public ready(): Promise<{String}> {
    return new Promise((resolve) => {
      resolve('READY');
    });
  }

  public registerBackButtonAction(fn: Function, priority?: number): Function {
    return (() => true);
  }

  public hasFocus(ele: HTMLElement): boolean {
    return true;
  }

  public doc(): HTMLDocument {
    return document;
  }

  public is(): boolean {
    return true;
  }

  public getElementComputedStyle(container: any): any {
    return {
      paddingLeft: '10',
      paddingTop: '10',
      paddingRight: '10',
      paddingBottom: '10',
    };
  }

  public onResize(callback: any) {
    return callback;
  }

  public registerListener(ele: any, eventName: string, callback: any): Function {
    return (() => true);
  }

  public win(): Window {
    return window;
  }

  public raf(callback: any): number {
    return 1;
  }

  public timeout(callback: any, timer: number): any {
    return setTimeout(callback, timer);
  }

  public cancelTimeout(id: any) {
    // do nothing
  }

  public getActiveElement(): any {
    return document['activeElement'];
  }
}

export class StorageMock {

  public get(key: string): Promise<{}> {
    return new Promise((resolve: Function) => {
      resolve({});
    });
  }

  public set(key: string, value: string): Promise<{}> {
    return new Promise((resolve: Function) => {
      resolve({key: key, value: value});
    });
  }

  public remove(key: string): Promise<{}> {
    return new Promise((resolve: Function) => {
      resolve({key: key});
    });
  }

  public query(): Promise<{ res: { rows: Array<{}> }}> {
    return new Promise((resolve) => {
      resolve({
        res: {
          rows: [{}]
        }
      });
    });
  }
}

export class MenuMock {
  public close(): any {
    return new Promise((resolve: Function) => {
      resolve();
    });
  }
}

export class AppMock {

  public getActiveNav(): NavMock {
    return new NavMock();
  }
}

/* tslint:enable */

2.根目录下新建文件夹 test-config,插入以下3个文件

1. karma.conf.js:
var webpackConfig = require('./webpack.test.js');

module.exports = function (config) {
  var _config = {
    basePath: '',

    frameworks: ['jasmine'],

    files: [
      {pattern: './karma-test-shim.js', watched: true}
    ],

    preprocessors: {
      './karma-test-shim.js': ['webpack', 'sourcemap']
    },

    webpack: webpackConfig,

    webpackMiddleware: {
      stats: 'errors-only'
    },

    webpackServer: {
      noInfo: true
    },

    browserConsoleLogOptions: {
      level: 'log',
      format: '%b %T: %m',
      terminal: true
    },

    coverageIstanbulReporter: {
      reports: [ 'html', 'lcovonly' ],
      fixWebpackSourcePaths: true
    },

    reporters: config.coverage ? ['kjhtml', 'dots', 'coverage-istanbul'] : ['kjhtml', 'dots'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false
  };

  config.set(_config);
};

2. karma-test-shim.js
Error.stackTraceLimit = Infinity;

require('core-js/es6');
require('core-js/es7/reflect');

require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');

var appContext = require.context('../src', true, /\.spec\.ts/);

appContext.keys().forEach(appContext);

var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');

testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());

3. webpack.test.js
var webpack = require('webpack');
var path = require('path');

module.exports = {
  devtool: 'inline-source-map',

  resolve: {
    extensions: ['.ts', '.js']
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        loaders: [
          {
            loader: 'ts-loader'
          } , 'angular2-template-loader'
        ]
      },
      {
       test: /.+\.ts$/,
       exclude: /(index.ts|mocks.ts|\.spec\.ts$)/,
       loader: 'istanbul-instrumenter-loader',
       enforce: 'post',
       query: {
         esModules: true
       }
     },
      {
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'null-loader'
      }
    ]
  },

  plugins: [
    new webpack.ContextReplacementPlugin(
      // The (\\|\/) piece accounts for path separators in *nix and Windows
      /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
      root('./src'), // location of your src
      {} // a map of your routes
    )
  ]
};

function root(localPath) {
  return path.resolve(__dirname, localPath);
}

三、添加命令行到package.json

  1. 在scripts项最后添加:
"test": "karma start ./test-config/karma.conf.js --coverage"

然后就可以使用npm test 运行

四、单元测试文件的注意事项

  1. 文档名格式为 *.spec.ts

  2. 避免typescript 检测报错项目启动不了, 在tsconfig.json 内的exclude加入 "src/*/.spec.ts",

  3. 与angular2 单元测试文档 相比,对组件的测试需要另外配置以下平台内容:

import { App, Config, Form, IonicModule, Keyboard, DomController, MenuController, NavController, Platform, NavParams, GestureController } from 'ionic-angular';
import { ConfigMock, PlatformMock, NavMock } from ‘mocks的相对路径’;
  • TestBed.configureTestingModule如下配置:
TestBed.configureTestingModule({
      declarations: [‘XX’], // 需要测试的模块名      
      providers: [
        App, DomController, Form, Keyboard, NavController,GestureController,ValidateService,
        {provide: Config, useClass: ConfigMock},
        {provide: Platform, useClass: PlatformMock},
        {provide: NavParams, useClass: NavMock}
      ],
      imports: [
        IonicModule,
      ],
    })

简单例子

在src文件内新建文件 1st.spec.ts
describe('1st tests', () => {
  it('true is true', () => expect(true).toBe(true));
});

然后运行 npm test 即可

相关

比较好的github上单元测试例子

Done!

如果觉得文章对你有点用的话,麻烦拿出手机,这里有一个你我都有的小福利(每天一次): 打开支付宝首页搜索“8601304”,即可领红包。谢谢支持

相关文章

网友评论

    本文标题:Ionic单元测试前期配置

    本文链接:https://www.haomeiwen.com/subject/iaoajxtx.html