问题
In Google Apps Script, I'm unit-testing an app that I'm working on, using QUnit, using test-driven-development.
The code under test
I am, right now, working on fully testing, and then developing, the following function:
/**
*
* Creates a Sheet from a long string of data
* @param { string } data : the long string of data
* @returns { Sheet } the newly-created Sheet
**/
function createSheetFrom(data) {
// if data is not in the form of a string, we've got a problem
if (data !== data.toString())
throw TypeError("Data must be in the form of a string")
// parse the data into SheetData
sheetData = SheetData.parse(data);
// create a new Sheet
newSheet = SPREADSHEET.insertSheet(sheetData.projectName)
// create title rows for it
createTitleRow(sheet)
return newSheet
}
where SPREADSHEET
is the Spreadsheet
the script is attached to, saved as a global variable for convenience.
That function depends on, among a few others, the one right below it, which has been successfully fully tested and developed:
/**
* Creates a title row for the spreadsheet
*
* @param { Sheet } sheet : the spreadsheet to create a title row for
* @returns { Sheet } the sheet for chaining purposes
**/
function createTitleRow(sheet) {
// declare the titles
var titles = ["File", "Total Cyclomatic Complexity", "Already unit-tested?", "Status Date"];
// insert a row right at the beginning
sheet.insertRows(1);
var titleRow = sheet.getRange(1, 1, 1, titles.length);
// set some values on titleRow
titleRow.setValues(titles);
titleRow.setHorizontalAlignment(CENTER)
return sheet;
}
The tests:
My test against createSheetFrom is thus:
function testCreateSheetFrom() {
var globalSpreadsheet // for storing the state of SPREADSHEET
var sheet // a stub Sheet
var createTitleRowCalls = []
var titleRowFunction
QUnit.test("testing createSheetFrom with 'file contents' that is simply one line of output",
function() {
throws(function() {
val = createSheetFrom("3 blah funcName c:/blah/foo/bar");
}, "Exception caught successfully")
})
}
...and the one against createTitleRow is thus:
function testCreateTitleRow() {
var sheet // spy for the Sheet object from the Google Spreadsheet API
QUnit.testStart(function() {
// create a sheet spy
sheet = {
insertRowsCalls : [],
insertRows : function(idx) {
Logger.log("insertRows called")
this.insertRowsCalls.push({ args : idx });
},
getRangeCalls : [],
range : {
setValuesCalls : [],
setValues : function(arr) {
if (!Array.isArray(arr)) return;
// simply record the args that this was called with
this.setValuesCalls.push({ args : arr });
},
setHorizontalAlignment: function(setting) {}
},
// method stub
getRange : function(r0,c0,r1,c1) {
Logger.log('getRange called')
this.getRangeCalls.push({ args : Array.prototype.splice.call(arguments, 0) });
return this.range;
}
};
})
QUnit.test("testing createTitleRow",
function() {
// hit the method under test
val = createTitleRow(sheet);
// the methods better have been hit
equal(sheet.insertRowsCalls.length, 1, "sheet.insertRows only got invoked once")
ok(sheet.getRangeCalls, "sheet.getRange() got invoked at least once")
ok(sheet.getRangeCalls.length)
deepEqual(sheet.getRangeCalls[0].args.filter(function(val, key) { return key < 3 }), [1,1,1], "the right arguments got sent to sheet.getRange()")
setValuesCalls = sheet.range.setValuesCalls
ok(setValuesCalls.length, "A call was made to sheet.range.setValues")
equal(setValuesCalls[0].args.length, 4, "The call was made with four args, as we expect")
// sheet better have been returned
equal(val, sheet, "createTitleRow() returns the sheet for testing, as promised")
})
}
The tests all pass:
However, when I add to the tests against createSheetFrom
the following sanity test, stubbing out createTitleRow
in the setup, reverting it back to its real self in the teardown, both the tests against createSheetFrom
and createTitleRow
break!
The code for that breaking test:
QUnit.testStart(function() {
// create a spy out of sheet
sheet = {
}
// replace SPREADSHEET with a spy
globalSpreadsheet = SPREADSHEET
SPREADSHEET = {
insertSheetCalls : [],
insertSheet : function(str) {
this.insertSheetCalls.push({ args: str })
return sheet
}
}
// stub out the dependencies
titleRowFunction = createTitleRow
createTitleRow = function(sheet) {
createTitleRowCalls.push({ args : sheet })
return sheet
}
})
QUnit.test("SanityTesting createSheetFrom",
function() {
projectName = "main"
complexity = 3
packageName = "main"
funcName = "SetContext"
filename = "main.go"
fileContents = createFileContents(projectName,
createLineOfTextFrom(complexity, packageName, funcName, "C:/Users/mwarren/Desktop/" + filename))
sheet = createSheetFrom(fileContents)
ok(SPREADSHEET.insertSheetCalls.length, "SPREADSHEET.insertSheet got called")
})
QUnit.testDone(function() {
// set SPREADSHEET back
SPREADSHEET = globalSpreadsheet
// set the dependencies back
createTitleRow = titleRowFunction
})
Screenshots of the test regressions:
I don't know why these regressions are happening, especially since I set back the changes I made in setup...
The states of the objects used are carrying over to other test cases in other test functions, despite me using testDone
to set the states of the objects back. This is now happening in other test cases, too
来源:https://stackoverflow.com/questions/52561975/qunit-stubbing-out-methods-on-a-dependency-breaks-tests-against-that-dependency