QUnit stubbing out methods on a dependency breaks tests against that dependency

为君一笑 提交于 2019-12-14 01:34:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!