如何对复杂的承诺链进行单元测试?
How can I unit test a complex promise chain?
我有一些 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);
});
});
});
像这样进行单元测试的正确方法是什么?
所以对于初学者来说,您可能想要打破您的承诺链以使您的代码的离散单元更加明显。我做了一些快速的 psuedo javascript(最熟悉的 w/ 节点,如果这不适合 vanilla 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;
});
现在就单元测试而言 - 您希望测试它的离散单元,因此以下用例似乎是合理的:
- 我能按预期得到任何结果吗?
- 如果我给它特定的值,它们是否按照我期望的方式排序?
- 如果两个查询都没有结果,它会中断吗?应该吗?
您可能需要从逻辑中分离出数据库调用并将结果传递到方法中,这样可以更轻松地测试某些场景。
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)
})
// ...
现在您可以单独和隔离地测试每个功能,以确保它们按照您的预期运行
我有一些 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);
});
});
});
像这样进行单元测试的正确方法是什么?
所以对于初学者来说,您可能想要打破您的承诺链以使您的代码的离散单元更加明显。我做了一些快速的 psuedo javascript(最熟悉的 w/ 节点,如果这不适合 vanilla 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;
});
现在就单元测试而言 - 您希望测试它的离散单元,因此以下用例似乎是合理的:
- 我能按预期得到任何结果吗?
- 如果我给它特定的值,它们是否按照我期望的方式排序?
- 如果两个查询都没有结果,它会中断吗?应该吗?
您可能需要从逻辑中分离出数据库调用并将结果传递到方法中,这样可以更轻松地测试某些场景。
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)
})
// ...
现在您可以单独和隔离地测试每个功能,以确保它们按照您的预期运行