TestIt Suite Runner

TestIt มีปัญหาอย่างนึงที่ยังแก้ไม่ได้คือ เมื่อเอาหลายๆ test มารันด้วยกันพร้อมกันบางครั้งทำให้ test ที่เคยทำงานผ่านกลับไม่ผ่าน เวลาเรียกรวมเลยต้องแยก test เหล่านั้นออกแต่ด้วยความขี้เกียจยังคงอยากเรียกที่เดียวแล้วเห็นผลลัพธ์ทั้งหมด เลยเขียน script เล็กๆเพื่อมาเรียกพวกนั้นรวมทีนึง เวลาใช้ก็เพียงแค่

node suite.js summary

แต่ยังมี config อีกเล็กน้อย ต้องสร้าง suite.js (หรือจะชื่ออะไรก็แล้วแต่) เป็นไฟล์ที่บอกว่าจะเรียก test ไหนให้ทำงานร่วมกันบ้าง หน้าตาก็อย่างด้านล่าง

var suite = {
  description: 'Suite description',
  runner: function() {
    require('./testunit1');
    require('./testunit2');
  }
}

exports.suite = suite;

สุดท้ายแล้ว เอา suite ไปเพิ่มในไฟล์ด้านล่าง (ไว้แยกออกมาและทำงานได้บน Browser ทีหลังละกัน)

var spawn = require('child_process').spawn;

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }

var HELP_OPTION = 'help';
var reserve = {
  all: true,
  help: true,
  summary: true
}

var beginPattern = /^begin test: .+$/;
var testPattern = /^.+: .+: (pass|fail).* \(\d+ assertion(s){0,1} run\)$/i;
var endPattern = /(Fail.|Pass.|Error!) \(\d+ tests: (\d+ passed){0,1}(, ){0,1}(\d+ failed){0,1}(, ){0,1}(\d+ errored){0,1}\)/i;

var modules = {
  // Show help
  help: {
    description: 'Show this help',
    runner: function() {
      var count = 1;

      console.error('Please specify module from this list.');
      for (var key in modules) {
        console.error(' ' + count + '. ' + key + ': ' +
                      modules[key].description);
        count++;
      }
    }
  },
  // Run all tests
  all: {
    description: 'Run all test (can use "node runtest.js all ' +
                 'summary" or "node runtest.js summary to see summary only)',
    runner: function(summary) {
      var onlySummary = false;
      if (process.argv.length == 4) {
        onlySummary = process.argv[3] == 'summary';
      } else if (summary) {
        onlySummary = summary;
      }

      var outputs = {};

      for (var name in modules) {
        if (!reserve[name]) {
          outputs[name] = { running: true, output: '' };

          var module = spawn(process.argv[0], [process.argv[1], name]);
          module.name = name;
          module.stdout.setEncoding('utf8');
          module.stdout.on('data', function(data) {
            var lines = data.split('\n');
            for (var key in lines) {
              var line = lines[key].trim();
              if (beginPattern.test(line)) {
                var child = line.substring('begin test: '.length).trim();
                this.name = child;
              }

              if (testPattern.test(line) && !onlySummary) {
                outputs[this.name].output += line + '\n';
              }

              if (endPattern.test(line)) {
                outputs[this.name].output += '(' + this.name + ')' + line;
              }
            }
          });

          module.on('exit', function(code) {
            outputs[this.name].running = false;
          });
        }
      }

      var interval = setInterval(function() {
        var allFalse = false;

        for (var module in outputs) {
          allFalse = allFalse || outputs[module].running;

          if (!outputs[module].running && !outputs[module].print) {
            console.log(outputs[module].output);
            outputs[module].print = true;
          }
        }

        if (!allFalse) {
          clearInterval(interval);
          console.log('done');
        }
      }, 100);

    }
  },
  // Summary run
  summary: {
    description: 'Run all test to see summary only',
    runner: function() {
      modules.all.runner(true)
    }
  },
  // Add more suite here
  suite1: require('module1').suite,
  suite2: require('module2').suite
}

var main = function(argv) {
  if (argv.length < 3) {
    modules.all.runner();
  } else {
    var module = argv[2];
    if (!modules[module]) {
      modules.help.runner();
    } else {
      if (module == HELP_OPTION) {
        modules.help.runner();
      } else {
        console.log('begin test: ' + module);
        modules[module].runner();
      }

    }

  }
}

main(process.argv);

save file ด้านบนเอาไปเรียกใช้ตามสะดวก วิธีเรียกก็มี

  1. node suite.js all ที่จะเห็นผลลัพธ์แบบละเอียด (แสดงแต่ละ test ว่าอะไรผ่านไม่ผ่านบ้าง)
  2. node suite.js summary เพื่อดูแค่ว่ามี suite ไหนผ่านไม่ผ่านบ้าง
  3. node suite.js suite เพื่อเรียกเฉพาะ suite ที่ต้องการ

สิ่งที่ยังไม่ได้ทำ ถ้าไม่ขี้เกียจจะทำเพิ่ม

  • แยก suite config ออกมาเป็นอีกไฟล์
  • ทำให้ทำงานผ่าน Browser ได้

About llun

Just a programmer

, ,