我如何对复杂的承诺链进行单元测试?

时间:2016-05-27 23:32:01

标签: javascript unit-testing promise mocha

我有一些JavaScript代码:

var findLeastUsedPassage;

findLeastUsedPassage = function(StudentId) {
  var passageCounts;
  passageCounts = [];
  return db.Passage.findAll({
    where: {
      active: true
    }
  }).each(function(dbPassage) {
    var passage;
    passage = dbPassage.get();
    passage.count = 0;
    return passageCounts.push(passage);
  }).then(function() {
    return db.Workbook.findAll({
      where: {
        SubjectId: 1,
        gradedAt: {
          $ne: null
        },
        StudentId: StudentId
      },
      include: [
        {
          model: db.WorkbookQuestion,
          include: [db.Question]
        }
      ],
      limit: 10,
      order: [['gradedAt', 'DESC']]
    });
  }).each(function(dbWorkbook) {
    return Promise.resolve(dbWorkbook.WorkbookQuestions).each(function(dbWorkbookQuestion) {
      var passageIndex;
      passageIndex = _.findIndex(passageCounts, function(passageCount) {
        return passageCount.id === dbWorkbookQuestion.Question.PassageId;
      });
      if (passageIndex !== -1) {
        return passageCounts[passageIndex].count++;
      }
    });
  }).then(function() {
    passageCounts = _.sortBy(passageCounts, 'count');
    return passageCounts;
  });
};

我想对它进行单元测试(我认为)。我指导mocha进行测试,但我的测试看起来并不是那么彻底:

describe('Finding the least used Passage', function() {
  it('should have a function called findLeastUsedPassage', function() {
    return expect(WorkbookLib.findLeastUsedPassage).to.exist;
  });
  return it('should return the least used passages for a student', function() {
    return WorkbookLib.findLeastUsedPassage(10).then(function(passageCounts) {
      var passageCountsLength;
      passageCountsLength = passageCounts.length;
      expect(passageCountsLength).to.equal(74);
      expect(passageCounts[0].count).to.be.at.most(passageCounts[1].count);
      expect(passageCounts[1].count).to.be.at.most(passageCounts[5].count);
      expect(passageCounts[56].count).to.be.at.most(passageCounts[70].count);
      return expect(passageCounts[70].count).to.be.at.most(passageCounts[73].count);
    });
  });
});

什么是正确的单元测试方法?

2 个答案:

答案 0 :(得分:4)

This是了解如何分解代码以便对其进行测试的绝佳资源。

目前,您的代码无法通过良好的测试,因为逻辑在多个数据库调用,业务逻辑和粘合代码之间都是混合的。您需要做的就是将其全部分解为多个命名函数,每个do one thing,就像您现在一样。期望不是在链中创建函数,而是应该在链外创建它们,然后在promise链中调用它们。

var passageCounts = [];


function findAllActivePassages() {
  passageCounts = [];

  return db.Passage.findAll({
    where: {
      active: true
    }
  })
}

function countPassages(dbPassage) {
  var passage;
  passage = dbPassage.get();
  passage.count = 0;
  return passageCounts.push(passage);
}

function findAllSubjects(StudentId) {
  return db.Workbook.findAll({
    where: {
      SubjectId: 1,
      gradedAt: {
        $ne: null
      },
      StudentId: StudentId
    },
    include: [
      {
        model: db.WorkbookQuestion,
        include: [db.Question]
      }
    ],
    limit: 10,
    order: [['gradedAt', 'DESC']]
  });
}) 

// ...

findAllActivePassages()
  .each(countPassages)
  .then(function() {
    return findAllSubjects(studentId)
  })
  // ...

现在,您可以单独并单独测试每个功能,以确保它们能够达到预期效果

答案 1 :(得分:1)

首先,对于初学者,您可能希望打破您的承诺链,使代码的离散单位更加明显。我做了一些快速的psuedo javascript(大多数familliar w / node如此道歉,如果这不适合香草javascript干净)。

var p1 = db.Passage.findAll({ where: { active: true }})
var p2 = db.Workbook.findAll({
      where: {
        SubjectId: 1,
        gradedAt: {
          $ne: null
        },
        StudentId: StudentId
      },
      include: [
        {
          model: db.WorkbookQuestion,
          include: [db.Question]
        }
      ],
      limit: 10,
      order: [['gradedAt', 'DESC']]
    });

Promise.all([p1, p2])
.then(function(results){
    var passages = results[0]
    var workbooks = results[1];

    var passageCounts = {};
    passages.foreach(function(passage){
        passagecounts[passage.get().id] = 0
    });

    workbooks.foreach(function(workbook){
        workbook.workBookQuestions.foreach(function(question){
            return passageCounts[dbWorkbookQuestion.Question.PassageId] += 1;
        })
    });

    return Promise.resolve(passageCounts)
}).then(function(passageCounts){
    passageCounts = _.sortBy(passageCounts, 'count'); //this has to change but don't know what underscore offers for sorting an object used as a hashmap
    return passageCounts;
});

现在就单元测试而言 - 您正在寻找测试它的离散单元,以便以下用例看似合理:

  • 我预计会得到任何结果吗?
  • 如果我给它具体的值,它们是按照我期望的方式排序的吗?
  • 如果我对这两个查询都没有结果,它会破坏吗?应该吗?

您可能有必要从逻辑中分解数据库调用并将结果传递给方法,从而使某些方案的测试更容易一些。