在测试执行之前从模块加载数据

load data from module before test executes

本文关键字:模块 加载 数据 测试 执行      更新时间:2023-09-26

(我最近问了这个问题并接受了答案,但这仍然不是我需要的。)我真的需要从模块加载的数据创建动态测试。数组中的每个项都将有自己的describe语句和某些量角器操作。我之前的帖子有一个答案,说要使用it语句,但我不能这样做,因为有太多的事情要做

我的主要问题是数据没有及时加载到describe。我有另一个建议,使用VCR.js或类似的东西,但我认为这些不会起作用,因为我使用的是一个模块。有没有一种方法可以将数据保存到一个单独的文件中并加载?这是个好办法吗?

var data = require('get-data'); //custom module here
describe('Test', function() {
  var itemsArr;
  beforeAll(function(done) { 
    data.get(function(err, result) {
      itemsArr = result; //load data from module
      done();
    });
  })
  //error: Cannot read property 'forEach' of undefined
  describe('check each item', function() {
    itemsArr.forEach(function(item) {
      checkItem(item);
    });
  });
  function checkItem (item) {
    var itemName = item.name;
    describe(itemName, function() {
      console.log('describe');
      it('should work', function() {
        console.log('it');
        expect(true).toBeTruthy();
      });
    });
  }
});

更新:

我用了尤金的答案,想出了这个。我无法按照自己的意愿测试每项研究,因为it语句不会触发。这个问题可以解决吗??

describe('check each item', function () {
   it('should load data', function (done) {
      browser.wait(itemsPromise, 5000);
     itemsPromise.then(function(itemsArr) {
       expect(itemsArr).toBeTruthy();
       studyArr = itemsArr.filter(function (item) {
         return item.enabled && _.contains(item.tags, 'study');
       });
       studyCount = studyArr.length;
       expect(studies.count()).toEqual(studyCount);
       checkItems(studyArr);
       done();
     });
   });
   function checkItems (itemsArr) {
     itemsArr.forEach(function (item) {
       describe(item.id, function () {
        console.log('checkItems', item.id);
        // doesn't work
         it('should work', function (done) {
           expect(false).toBeTruthy();
           done();
         });
       });
     });
   }
 });

您正在尝试做Jasmine不允许的事情:在测试套件启动后生成测试。请参阅关于Jasmine问题的评论:

Jasmine不支持在套件开始运行后添加规范。通常,当我需要这样做的时候,我能够提前知道选项列表,并通过循环进行it调用。[…]

("添加规格"==="添加测试")

关键是可以动态生成测试,但只能在测试套件开始执行测试之前。由此得出的一个推论是,测试生成不能是异步的。

您的第二次尝试不起作用,因为它试图将测试添加到已经运行的套件中。

您的第一次尝试更接近您的需求,但也不起作用,因为describe会立即调用其回调,因此在describe尝试生成测试时,beforeAll尚未运行。

解决方案

这一切都归结为在测试套件开始执行测试之前计算itemsArr的值。

您可以创建一个.getSync方法来同步返回结果。然后,您的代码将类似于:

var data = require('get-data'); //custom module here
var itemsArr = data.getSync();
describe('Test', function() {
  describe('check each item', function() {
    itemsArr.forEach(function(item) {
      checkItem(item);
    });
  });
[...]

如果无法编写.getSync函数,可以让一个外部进程负责生成JSON输出,然后将其反序列化为itemsArr。您可以使用child_process的一个...Sync函数来执行这个外部进程。

以下是第二个选项如何工作的示例。我用以下代码创建了一个get-data.js文件,该文件使用setTimeout模拟异步操作:

var Promise = require("bluebird"); // Bluebird is a promise library.
var get = exports.get = function () {
    return new Promise(function (resolve, reject) {
        var itemsArr = [
            {
                name: "one",
                param: "2"
            },
            {
                name: "two",
                param: "2"
            }
        ];
        setTimeout(function () {
            resolve(itemsArr);
        }, 1000);
    });
};
// This is what we run when were are running this module as a "script" instead
// of a "module".
function main() {
    get().then(function (itemsArr) {
        console.log(JSON.stringify(itemsArr));
    });
};
// Check whether we are a script or a module...
if (require.main === module) {
    main();
}

然后,在规范文件中:

var child_process = require('child_process');
var itemsArr = JSON.parse(child_process.execFileSync(
    "/usr/bin/node", ["get-data.js"]));
describe('Test', function() {
    itemsArr.forEach(function(item) {
        checkItem(item);
    });
    function checkItem (item) {
        var itemName = item.name;
        describe(itemName, function() {
            console.log('describe');
            it('should work', function() {
                console.log('it');
                expect(true).toBeTruthy();
            });
        });
    }
});

我已经使用jasmine-node测试了上面的代码。以及以下文件结构:

.
├── data.js
├── get-data.js
└── test
    └── foo.spec.js

./node_modulesbluebirdjasmine-node。这就是我得到的:

$ ./node_modules/.bin/jasmine-node --verbose test 
describe
describe
it
it
Test - 5 ms
    one - 4 ms
        should work - 4 ms
    two - 1 ms
        should work - 1 ms
Finished in 0.007 seconds
2 tests, 2 assertions, 0 failures, 0 skipped

尝试使用promise,比如:

  var deferred = protractor.promise.defer();
  var itemsPromise = deferred.promise;
  beforeAll(function() { 
    data.get(function(err, result) {
      deferred.fulfill(result);
    });
  })

然后:

  describe('check each item', function() {
    itemsPromise.then(function(itemsArr) {
        itemsArr.forEach(function(item) {
          checkItem(item);
        });
    });
  });

我能想到的另一个解决方案是使用browser.wait等待itemsArr不为空。

您的get-data模块是否使用量角器进行一些浏览器操作?如果是这样,您将需要在controlFlow的上下文中设置/获取itemsArr。否则,它将读取get-data模块中的所有代码,但推迟执行,而不是等到它完成后再直接转到那些期望语句。

var data = require('get-data'); //custom module here
var itemsArr;
describe('Test', function() {
  beforeAll(function() {
    // hook into the controlFlow and set the value of the variable
    browser.controlFlow().execute(function() {
      data.get(function(err, result) {
        itemsArr = result; //load data from module
      });
    });
  });
  //error: Cannot read property 'forEach' of undefined
  describe('check each item', function() {
    // hook into the controlFlow and get the value of the variable (at that point in time)
    browser.controlFlow().execute(function() {
      itemsArr.forEach(function(item) {
        checkItem(item);
      });
    });
  });
  function checkItem (item) {
    var itemName = item.name;
    describe(itemName, function() {
      console.log('describe');
      it('should work', function() {
        console.log('it');
        expect(true).toBeTruthy();
      });
    });
  }
});