编写单元测试

单元测试在Nightwatch 0.9版本已经得到了改进。现在在Nightwatch上编写的单元测试也与Mocha的导出接口完全兼容,因此你可以使用任何一个测试运行程序。事实上,所有Nightwatch单元测试都被重写了这样可以用Nightwatch或者Mocha来运行了。

为了向后兼容的原因,为了利用改进的单元测试支持,你需要在测试setting中设置compatible_testcase_support=true

在0.9版本之前编写的单元测试仍然可以继续工作,但是建议升级到最新版本的Nightwatch。

禁用automatic selenium session

Nightwatch会企图自动尝试连接到指定的selenium服务器,并创建一个会话。当运行单元测试时,需要在selenium设置中将start_session属性设置为false。

Assertion 框架

从0.9版本开始,在对单元测试的改进支持中,客户端对象不再作为测试的参数传递。现在传递的惟一参数是用于异步测试的done的回调。

你可以使用任何你喜欢的断言框架。比如Chai.js非常好,而且非常灵活。我们在Nightwatch单元测试中使用内部的Node.js assert。

你仍然可以在你的测试中通过这个引用client对象,比如 this.client

例子,这是Nightwatch模块中utils.js的一个子集:

var assert = require('assert');
var common = require('../../common.js');
var Utils = common.require('util/utils.js');

module.exports = {
  'test Utils' : {
    testFormatElapsedTime : function() {

      var resultMs = Utils.formatElapsedTime(999);
      assert.equal(resultMs, '999ms');

      var resultSec = Utils.formatElapsedTime(1999);
      assert.equal(resultSec, '1.999s');

      var resultMin = Utils.formatElapsedTime(122299, true);
      assert.equal(resultMin, '2m 2s / 122299ms');
    },

    testMakeFnAsync : function() {
      function asyncFn(cb) {
        cb();
      }

      function syncFn() {}

      var convertedFn = Utils.makeFnAsync(1, syncFn);
      var called = false;
      convertedFn(function() {
        called = true;
      });

      assert.equal(Utils.makeFnAsync(1, asyncFn), asyncFn);
      assert.ok(called);
    }
  }
};

异步单元测试

测试函数的参数done是可选的回调函数,它表示测试完成了。如果存在,则必须在异步操作结束时调用回调函数。

例子,这个单元测试检查如果Nightwatch在一段时间内不调用done的回调(10毫秒),是否会抛出一个错误。

module.exports = {
  var path = require('path');
  var assert = require('assert');
  var common = require('../../common.js');
  var CommandGlobals = require('../../lib/globals/commands.js');
  var Runner = common.require('runner/run.js');

  module.exports = {
    'testRunner': {
      before: function (done) {
        CommandGlobals.beforeEach.call(this, done);
      },

      after: function (done) {
        CommandGlobals.afterEach.call(this, done);
      },

      beforeEach: function () {
        process.removeAllListeners('exit');
        process.removeAllListeners('uncaughtException');
      },

      'test async unit test with timeout error': function (done) {
        var testsPath = path.join(__dirname, '../../asynchookstests/unittest-async-timeout.js');
        var globals = {
          calls : 0,
          asyncHookTimeout: 10
        };

        process.on('uncaughtException', function (err) {
          assert.ok(err instanceof Error);
          assert.equal(err.message, 'done() callback timeout of 10 ms was reached while executing "demoTest". ' +
            'Make sure to call the done() callback when the operation finishes.');

          done();
        });

        var runner = new Runner([testsPath], {
          seleniumPort: 10195,
          silent: true,
          output: false,
          persist_globals : true,
          globals: globals,
          compatible_testcase_support : true
        }, {
          output_folder : false,
          start_session : false
        });

        runner.run().catch(function(err) {
          done(err);
        });
      }
    }
  };
};

完整的test suit可以在GitHub上查看:https://github.com/nightwatchjs/nightwatch/tree/master/test/src/runner/testRunner.js

运行Nightwatch单元测试

为了了解如何使用Nightwatch代码运行单元测试,你可以转到GitHub页面,克隆项目,并按照测试说明来运行。

你也可以查看Nightwatch自己的完整test suit,例如:https://github.com/nightwatchjs/nightwatch/tree/master/test/src

以下是运行它们所需的配置:

{
  "src_folders" : ["./test/src"],
  "selenium" : {
    "start_process" : false,
    "start_session" : false
  },

  "test_settings" : {
    "default" : {
      "filter" : "*/.js",
      "compatible_testcase_support" : true
    }
  }
}

使用组合配置

下面是如何将E2E测试和单元测试结合在一起的一个示例,他们都配置在nightwatch.json文件中。注意使用exclude和filter属性。

一个空的exclude意味着我们想要重置它的值,这时候只依赖于filter。

{
  "src_folders" : ["./examples/tests", "./examples/unittests"],
  "output_folder" : "./examples/reports",

  "selenium" : {
    "start_process" : true,
    "server_path" : "./bin/selenium-server-standalone.jar",
    "log_path" : "",
    "host" : "127.0.0.1",
    "port" : 4444,
    "cli_args" : {
      "webdriver.chrome.driver" : "",
      "webdriver.ie.driver" : ""
    }
  },

  "test_settings" : {
    "default" : {
      "launch_url" : "http://localhost",
      "selenium_port"  : 4444,
      "selenium_host"  : "localhost",
      "silent": true,
      "screenshots" : {
        "enabled" : false,
        "path" : ""
      },
      "desiredCapabilities": {
        "browserName": "firefox",
        "javascriptEnabled": true,
        "acceptSslCerts": true
      },
      "exclude" : "./examples/unittests/*"
    },

    "unittests" : {
      "selenium" : {
        "start_process" : false,
        "start_session" : false
      },
      "filter" : "./examples/unittests/*",
      "exclude" : ""
    }
  }
}

代码覆盖率

目前,Nightwatch没有提供一个覆盖率reporter,计划在未来的版本里实现。同时,你可以编写一个定制的报告,它将输出覆盖率数据。详情参看custom repoter section和Mocha HTMLCov 关于reporter应该看起来是什么样。

results matching ""

    No results matching ""