【问题标题】:Jasmine toEqual for complex objects (mixed with functions)Jasmine toEqual 用于复杂对象(与函数混合)
【发布时间】:2013-01-26 20:32:07
【问题描述】:

目前,我有一个函数有时会返回一个包含一些函数的对象。使用expect(...).toEqual({...}) 时,它似乎与那些复杂的对象不匹配。具有函数或 File 类(来自输入类型文件)的对象,它就是不能。如何克服?

【问题讨论】:

    标签: jasmine matcher


    【解决方案1】:

    试试Underscore _.isEqual()函数:

    expect(_.isEqual(obj1, obj2)).toEqual(true);
    

    如果可行,您可以创建一个custom matcher

    this.addMatchers({
        toDeepEqual: function(expected) {
            return _.isEqual(this.actual, expected);
        };
    });
    

    然后您可以编写如下规范:

    expect(some_obj).toDeepEqual(expected_obj);
    

    【讨论】:

    • toEqual 给我同样的结果=> Error: Expected { exception : Function, data : Function, proxy : Function, remote : Function, append_args : Function, set_args : Function, get_args : Function, remove : Function, make : Function, unmake : Function } to deep equal { exception : Function, data : Function, proxy : Function, remote : Function, append_args : Function, set_args : Function, get_args : Function, remove : Function, make : Function, unmake : Function }.
    • 您比较的对象是否仅由函数组成?
    • 在那种特殊情况下,是的,但有时我有类以及普通对象和本机包装器,例如 FileFileList
    • 真棒(JSON.stringify)的作品......你接受修改后我会接受你的答案:)
    • 其实是不行,检查那个函数的输出后,显示为{},这明显是错误的,好像不能把函数转换成字符串(比如用@ 987654331@)
    【解决方案2】:

    正如 Vlad Magdalin 在 cmets 中指出的那样,将对象制作成 JSON 字符串,它可以像它一样深,以及函数和 File/FileList 类。当然,在函数上不用toString(),也可以直接叫'Function'

    function replacer(k, v) {
        if (typeof v === 'function') {
            v = v.toString();
        } else if (window['File'] && v instanceof File) {
            v = '[File]';
        } else if (window['FileList'] && v instanceof FileList) {
            v = '[FileList]';
        }
        return v;
    }
    
    beforeEach(function(){
        this.addMatchers({
            toBeJsonEqual: function(expected){
                var one = JSON.stringify(this.actual, replacer).replace(/(\\t|\\n)/g,''),
                    two = JSON.stringify(expected, replacer).replace(/(\\t|\\n)/g,'');
    
                    return one === two;
                }
        });
    });
    
    expect(obj).toBeJsonEqual(obj2);
    

    【讨论】:

    • 请注意 JSON.stringify 不保证属性顺序!因此比较生成的 JSON 可能会导致随机测试失败。这取决于底层的 javascript 运行器如何对属性进行排序。例如:测试可能在engineA(例如NodeJS)中运行时有效,但随后在engineB(例如Firefox)甚至在另一个engineA版本中中断。或者即使在相同版本的相同引擎中运行也会随机中断。
    【解决方案3】:

    如果有人像我一样使用 node.js,当我只关心比较简单属性而忽略所有功能时,我在 Jasmine 测试中使用以下方法。此方法需要json-stable-stringify,用于在序列化之前对对象属性进行排序。

    用法:

      var stringify = require('json-stable-stringify');
    
      var obj1 = {
        func: function() {
        },
        str1: 'str1 value',
        str2: 'str2 value',
        nest1: {
        nest2: {
            val1:'value 1',
            val2:'value 2',
            someOtherFunc: function() {
            }
          }
        }
      };
    
      var obj2 = {
        str2: 'str2 value',
        str1: 'str1 value',
        func: function() {
        },
        nest1: {
          nest2: {
            otherFunc: function() {
            },
            val2:'value 2',
            val1:'value 1'
          }
        }
      };
    
      it('should compare object properties', function () {
        expect(stringify(obj1)).toEqual(stringify(obj2));
      });
    

    【讨论】:

      【解决方案4】:

      扩展@Vlad Magdalin 的答案,这在 Jasmine 2 中有效:

      http://jasmine.github.io/2.0/custom_matcher.html

      beforeEach(function() {
        jasmine.addMatchers({
          toDeepEqual: function(util, customEqualityTesters) {
            return {
              compare: function(actual, expected) {
                var result = {};
                result.pass = _.isEqual(actual, expected);
                return result;
              }
            }
          }
        });
      });
      

      如果您使用 Karma,请将其放在启动回调中:

      callback: function() {
        // Add custom Jasmine matchers.
        beforeEach(function() {
          jasmine.addMatchers({
            toDeepEqual: function(util, customEqualityTesters) {
              return {
                compare: function(actual, expected) {
                  var result = {};
                  result.pass = _.isEqual(actual, expected);
                  return result;
                }
              }
            }
          });
        });
      
        window.__karma__.start();
      });
      

      【讨论】:

        【解决方案5】:

        这是我使用 Jasmine 2 语法的方法。

        我在../support/customMatchers.js 中创建了一个customMatchers 模块(我喜欢制作模块)。

        "use strict";
        
        /**
         *  Custom Jasmine matchers to make unit testing easier.
         */
        module.exports = {
          // compare two functions.
          toBeTheSameFunctionAs: function(util, customEqualityTesters) {
            let preProcess = function(func) {
              return JSON.stringify(func.toString()).replace(/(\\t|\\n)/g,'');
            };
        
            return {
              compare: function(actual, expected) {
                return {
                  pass: (preProcess(actual) === preProcess(expected)),
                  message: 'The functions were not the same'
                };
              }
            };
          }
        }
        

        然后在我的测试中使用如下:

        "use strict";
        
        let someExternalFunction = require('../../lib/someExternalFunction');
        let thingBeingTested = require('../../lib/thingBeingTested');
        
        let customMatchers = require('../support/customMatchers');
        
        describe('myTests', function() {
        
          beforeEach(function() {
            jasmine.addMatchers(customMatchers);
        
            let app = {
              use: function() {}
            };
        
            spyOn(app, 'use');
            thingBeingTested(app);
          });
        
          it('calls app.use with the correct function', function() {
            expect(app.use.calls.count()).toBe(1);
            expect(app.use.calls.argsFor(0)).toBeTheSameFunctionAs(someExternalFunction);
          });
        
        });
        

        【讨论】:

          猜你喜欢
          • 2020-03-04
          • 1970-01-01
          • 1970-01-01
          • 2014-04-20
          • 2018-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多