测试产生错误的promises和sync函数

时间:2015-03-31 16:10:47

标签: javascript node.js unit-testing promise bluebird

我正在尝试同时构建和测试一个函数。测试是有道理的,我在理论上喜欢它,但当它归结为它时,它总是背后的痛苦。

我有一个函数,当一些事情发生错误时会收到一个字符串并抛出错误它会返回原始的text参数,因此返回truthy值,如果没有它应该被捕获通过承诺,它既可以作为承诺,也可以作为承诺。

这是测试/我实际想做的事情(不起作用)。

var main = require("./index.js")
var Promise = require("bluebird")
var mocha = require("mocha")
var chai = require("chai")
var chaiPromise = require("chai-as-promised")
chai.use(chaiPromise)

var shouldThrow = [
  "random", // invalid non-flag
  "--random", // invalid flag
  "--random string", //invalid flag
  "--wallpaper", // invalid flag w/ match
  "--notify", // invalid flag w/ match
  "wallpaper", // valid non-flag missing option(s) image
  "wallpaper image.jpg" // invalid flag value
  "wallpaper http://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621", // invalid flag value
  "wallpaper //cdn.shopify.com/s/files/1/0031/5352/t/28/assets/favicon.ico?12375621748379006621", // invalid flag value
  "wallpaper http://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/favicon.ico?12375621748379006621",  // invalid flag value
  "wallpaper https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/favicon.ico?12375621748379006621",  // invalid flag value
  "wallpaper https://cdn.example.com/s/files/1/0031/5352/files/holstee_logo_2.png?4803", // invalid flag value
  "wallpaper https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue",  // invalid flag value
  "wallpaper https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue "+moment().subtract(1, "month").format("YYYY-MM-DD-HH-mm"),  // invalid flag value
  "wallpaper https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue "+moment().add(1, "month").format("YY-MM-DD-HH"), // invalid flag value
  "wallpaper --image http://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621", // invalid flag value not https
  "wallpaper --image //cdn.shopify.com/s/files/1/0031/5352/t/28/assets/favicon.ico?12375621748379006621", // invalid flag no protocol
  "wallpaper --image http://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/favicon.ico?12375621748379006621",  // invalid flag value not https
  "wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/favicon.ico?12375621748379006621",  // invalid flag value not valid image
  "wallpaper --image https://cdn.example.com/s/files/1/0031/5352/files/holstee_logo_2.png?4803", // invalid flag image not found
  "wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue",  // invalid subflag queue missing value
  "wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue "+moment().subtract(1, "month").format("YYYY-MM-DD-HH-mm"),  // invalid subflag queue date value is past
  "wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue "+moment().add(1, "month").format("YY-MM-DD-HH"), // invalid subflag queue date value format
  "--wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621", //no action non-flag
  "--wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue "+moment().add(1, "month").format("YYYY-MM-DD-HH-mm"), //no action non-flag
  "notify", // valid non-flag missing option(s) message, open
  'notify --message "Hello world"', // valid flag missing params open
  'notify --open "https://www.holstee.com"', // valid flag missing params message
  'notify --message "Hello world" --open "http://www.holstee.com"', // invalid subflag value `open` should be https
  'notify --message "Hello world" --open "https://www.holstee.com" --queue', // invalid subflag queue missing value
  'notify --message "Hello world" --open "https://www.holstee.com" --queue '+moment().subtract(1, "month").format("YYYY-MM-DD-HH-mm"), // invalid subflag queue date value is past
  'notify --message "Hello world" --open "https://www.holstee.com" --queue '+moment().add(1, "month").format("YY-MM-DD-HH"), // invalid subflag queue date value format
  '--notify --message "Hello world" --open "https://www.holstee.com"', //no action non-flag
  '--notify --message "Hello world" --open "https://www.holstee.com --queue "'+moment().add(1, "month").format("YYYY-MM-DD-HH-mm"), //no action non-flag
]

var shouldNotThrow = [
  'notify --message "Hello world" --open "https://www.holstee.com"',
  'notify --message "Hello world" --open "https://www.holstee.com --queue "'+moment().add(1, "month").format("YYYY-MM-DD-HH-mm"),
  "wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621",
  "wallpaper --image https://cdn.shopify.com/s/files/1/0031/5352/t/28/assets/holstee-calendar-2015-03-flow-desktop.jpg?12375621748379006621 --queue "+moment().add(1, "month").format("YYYY-MM-DD-HH-mm"),
]

describe('Process Text', function(){
  return Promise.map(shouldThrow, function(option){
    it('throw error', function(){
      return main.processText(option).should.throw()
    })    
  })
  return Promise.map(shouldNotThrow, function(option){
    it('throw error', function(){
      return main.processText(option).should.not.throw()
    })    
  })
})

这是我正在尝试测试的非工作*功能的快照。

main.processText = function(text){
  var args = minimist(text.split(" "))
  var actions = _.keys(actionsFlags)
  var flags = _.chain(_.map(actionsFlags, _.keys)).flatten().uniq().value()
  var extraUnparsed = _.extra(actions, args._)
  var providedFlags = _.chain(args).keys().without("_").value()
  var extraParsed = _.extra(flags, providedFlags)
  var validActions = _.intersection(actions, args._)
  var requiredFlags = _.mapObject(actionsFlags, function(flags){
    return _.filterObject(flags, function(flag){
      return flag
    })
  })
  if(extraUnparsed.length) throw new Error("invalid unparsed argument(s): "+extraUnparsed.join(", "))
  if(extraParsed.length) throw new Error("invalid parsed argument(s): "+extraParsed.join(", "))
  if(validActions.length > 1) throw new Error("too many actions: "+validActions.join(", "))
  if(validActions.length == 0) throw new Error("no action: "+actions.join(", "))
  _.each(actions, function(action){
    var missingFlags = _.missing(_.keys(requiredFlags[action]), providedFlags)
    var extraFlags = _.extra(_.keys(requiredFlags[action]), providedFlags)
    if(_.contains(args._, action)){
      if(missingFlags.length) throw new Error(util.format("missing required flags for %s: %s", action, missingFlags.join(", ")))
      if(extraFlags.length) throw new Error(util.format("extra flags for %s: %s", action, extraFlags.join(", ")))
    }
  })
  return text
}

请注意,这不是承诺,也不会返回任何承诺。我想要的一个验证功能是检查网址是否以200状态代码响应,这将是request承诺。如果我更新此函数,那么所有函数内容是否需要嵌套在Promise.resolve(false).then()中?也许承诺不应该在这个代码块中,并且所有async验证操作都应该存在于其他地方?

我不知道我在做什么,我有点沮丧。我当然正在寻找一些金色的子弹或任何能够理解这一切的东西。

理想情况下,我可以使用一些帮助来测试这种功能。如果我稍后将其变为承诺,我仍然希望我的所有测试都能正常运行。


以下是同步功能和承诺的一些示例代码。

function syncFunction(value){
  if(!value) throw new Error("missing value")
  return value
}

function asyncFunction(url){
  return requestPromise(url)
}

// Both of these will throw errors the same way they will be caught by the promise then you can use `.catch` (in bluebird). 

Promise.resolve(false).then(function(){
  return syncFunction()
})

Promise.resolve(false).then(function(){
  return asyncFunction("http://404.com")
})

我希望这能反映出我测试错误的方式,以及shouldshould not是否会在我的测试中引发错误。


我把承诺遗漏了,这是一个同步功能,我正在测试这个。

describe('Process Text', function(){
  _.each(shouldThrow, function(option){
    it('throw error ('+option+')', function(){
      expect(function(){
        main.textValidation(option)
      }).to.throw()
    })
  })
  _.each(shouldNotThrow, function(option){
    it('not throw error ('+option+')', function(){
      expect(function(){
        main.textValidation(option)
      }).to.not.throw()
    })
  })
})

1 个答案:

答案 0 :(得分:0)

强烈推荐npm install chai-as-promised

return doSomethingAsync().should.eventually.equal("foo");

https://github.com/domenic/chai-as-promised