测试 IIFE(立即调用函数表达式)的最佳方法

Ian*_*hel 3 javascript unit-testing mocha.js iife

所以我有一个现有的应用程序,它在浏览器中广泛使用 IIFE。我正在尝试在代码中引入一些单元测试,并保持 IIFE 模式以对代码库进行新的更新。除此之外,我什至无法编写一个测试来处理代码。例如,我在代码库中看到了这种类型的逻辑:

var Router = (function (router) {

   router.routeUser = function(user) {
      console.log("I'm in! --> " + user)
   };

   return router;
})(Router || {});
Run Code Online (Sandbox Code Playgroud)

然后将 JS 文件包含在标记中的脚本标记中:

<script src="js/RouteUser.js"></script>
Run Code Online (Sandbox Code Playgroud)

并在生产代码中这样调用:

Router.routeUser(myUser)
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,我该如何编写测试routeUser方法的测试?我在摩卡测试中试过这个:

var router = require('../../main/resources/public/js/RouteUser');

suite('Route User Tests', function () {
    test('Route The User', function () {
        if (!router)
            throw new Error("failed!");
        else{
            router.routeUser("Me")
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

但我得到一个例外:

TypeError: router.routeUser is not a function
at Context.<anonymous> (src\test\js\RouteUser.test.js:8:20)
Run Code Online (Sandbox Code Playgroud)

然后我尝试返回该方法,它给出了相同的错误:

var Router = (function (router) {
    return {
        routeUser: function (user) {
            console.log("I'm in! --> " + user)
        } 
    }
}
)(Router || {});
Run Code Online (Sandbox Code Playgroud)

任何人都可以在这里指出我正确的方向吗?

Kos*_*Kos 5

听起来是...

  • 您有一个仅在浏览器上下文中使用的脚本代码库(IIFE 的使用表明了这一点)
  • 您想使用 node.js 引入无浏览器单元测试(Jest、Mocha?)(好主意!)
  • 但此时您可能不想将整个代码库迁移到不同的编码风格(根据代码库的大小,可能需要做很多工作)

鉴于这些假设,问题在于您希望您的代码...

  • 在生产中使用时充当脚本(设置全局window.Router等)
  • 作为一个模块在单元测试中使用时,这样就可以require()它在单元测试

UMD

UMD,或通用模块定义,曾经是编写代码的常用方法,以便它可以在多种环境中工作。有趣的方法,但非常麻烦,我喜欢认为 UMD 现在已经成为过去式......

为了完整起见,我将其留在这里。

就拿UMD的想法

如果您现在唯一想让特定脚本也充当模块的事情,以便它可以在测试中导入,您可以做一个小调整:

var Router = (function (router) {

   router.routeUser = function(user) {
      console.log("I'm in! --> " + user)
   };

   if (typeof exports === "object") {
      module.exports = router;
      // now the Mocha tests can import it!
   }
   return router;
})(Router || {});
Run Code Online (Sandbox Code Playgroud)

长期解决方案

从长远来看,通过重写所有代码以仅使用模块并使用诸如webpack为您打包之类的工具,您可以获得很多好处。上述想法是朝着您的方向迈出的一小步,它为您提供了一个特定的好处(可测试性)。但这不是一个长期的解决方案,您在处理依赖项时会遇到一些问题(如果您的路由器希望某些全局变量就位怎么办?)


jef*_*han 1

如果您打算在浏览器中运行 Mocha 测试,则无需更改现有代码。

让我们来看看 IIFE 模式,因为根据您的代码,我认为您可能会误解它的工作原理。基本形状是这样的:

var thing = (function() {

   return 1;

})();

console.log(thing) // '1'
Run Code Online (Sandbox Code Playgroud)

它是一个等于等号右侧值的var声明设置。thing右侧,第一组括号包装了一个函数。然后,第二组括号位于它旁边,最后。第二组调用第一组括号中包含的函数表达式。这意味着return函数的值将是语句中右侧的值var。所以thing等于1.

在您的情况下,这意味着外部Router变量设置为等于router函数返回的变量。Router这意味着在将脚本包含在 DOM 中之后,您可以像在测试中一样访问它:

suite('Route User Tests', function () {
    test('Route The User', function () {
        if (!Router) // <- Notice the capital 'R'
            throw new Error("failed!");
        else {
            Router.routeUser("Me") // <- capital 'R'
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

如果您打算使用节点运行测试,请参阅 Kos 的答案。