【问题标题】:How can I spy on a getter property using jasmine?如何使用 jasmine 监视 getter 属性?
【发布时间】:2016-01-13 21:48:57
【问题描述】:

如何使用 jasmine 监视 getter 属性?

var o = { get foo() {}, };

spyOn(o, 'foo').and.returnValue('bar'); // Doesn't work.

这也不起作用 AFAICT:

spyOn(Object.getOwnPropertyDescriptor(o, 'foo'), 'get').and.returnValue('bar');

【问题讨论】:

  • this similar question 的讨论中,你不能。 Getter 和 setter 不被视为标准方法(例如,它们不需要作为函数调用。)
  • 也许您可以根据不同的对象状态测试检索值的结果。
  • 根据这里的cmets,显然没有实现,但理论上也不是不可能。 spyOn(Object.getOwnPropertyDescriptor(o, 'foo'), 'get') 不起作用的原因是因为spyOn 将对象的属性重写为包装现有函数的新函数。更改getOwnPropertyDescriptor 返回的属性描述符对象不会更改实际属性。但是,您可以更改 Jasmine 以检测 setter/getter 并使用 defineProperty 实际重写该属性。如果对您很重要,也许可以打开一个功能请求?
  • @apsillers 请让您的评论成为答案。
  • 我已经打开了一个功能请求:github.com/jasmine/jasmine/issues/943

标签: javascript jasmine


【解决方案1】:

我不相信你可以监视吸气剂。 getter 的关键在于它的行为与属性完全一样,所以当它从未像函数一样被调用而是像属性一样被访问时,jasmine 如何能够监视它。

作为一种解决方法,您可以让您的 getter 调用另一个函数并监视它。

var o = {
     _foo: function(){
        return 'foo'; 
     }, 
     get foo(){
        return this._foo();
     }
};

spyOn(o, '_foo').and.returnValue('bar'); 

【讨论】:

    【解决方案2】:

    自 Jasmine 2.6 以来,spyOnProperty 已成为可能。要监视 foo 属性的访问器,请执行以下操作:

    spyOnProperty(o, 'foo')
    

    这允许您用 spy 函数替换访问器属性的 set 和/或 get 访问器函数。您只能指定或setget 作为第三个参数:

    spyOnProperty(o, 'foo', 'get')
    

    如果您因使用较早版本而无法升级,您可以将pull request that added this feature 合并到您的本地代码副本中。

    【讨论】:

    • 如果accessor 未设置为configurable:true,我是否认为这将失败?这意味着如果您试图监视未指定的第三方访问器,那么您就不走运了?
    • @james 我认为 Jasmine 永远无法监视不可配置的属性(无论是基于访问器的属性还是传统的数据属性)。 (我不是 100%,目前无法测试,但所有间谍活动都是基于财产替换。)
    【解决方案3】:

    我从@apsillers 的回复中获得灵感,并编写了以下帮助程序(要求 prop 如上所述可配置)

    let activeSpies = [];
    let handlerInstalled = false;
    
    function afterHandler() {
        activeSpies.forEach(({ obj, prop, descriptor }) => Object.defineProperty(obj, prop, descriptor));
        activeSpies = [];
    }
    
    
    export function spyOnGetter(obj, prop) {
        const env = jasmine.getEnv();
        const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
        const spy = jasmine.createSpy(`${prop} spy`);
        const copy = Object.assign({}, descriptor, { get: spy });
        Object.defineProperty(obj, prop, copy);
        activeSpies.push({
            obj,
            prop,
            descriptor,
        });
    
        if (!handlerInstalled) {
            handlerInstalled = true;
            env.afterEach(() => afterHandler());
        }
        return spy;
    }
    

    而且可以这样使用:

    import { spyOnGetter } from spyExtra;
    it('tests the thing', () => {
        spyOnGetter(myObj, 'myProp').and.returnValue(42);
        expect(myObj.myProp).toBe(42);
    });
    

    希望有用!

    【讨论】:

    • jasmine版本升级不了真的好用!!
    【解决方案4】:

    2017 年 2 月,他们合并了一个 PR 添加此功能,并于 2017 年 4 月发布。

    所以要监视您使用的 getter/setter: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); 其中 myObj 是您的实例,“myGetterName”是您的类中定义为 get myGetterName() {} 的实例的名称,第三个参数是 getset 的类型。

    您可以使用与spyOn 创建的间谍相同的断言。

    所以你可以例如:

    const spy = spyOnProperty(myObj, 'myGetterName', 'get'); // to stub and return nothing. Just spy and stub.
    const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.returnValue(1); // to stub and return 1 or any value as needed.
    const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.callThrough(); // Call the real thing.
    

    如果您有兴趣,可以在 github 源代码中使用此方法。

    https://github.com/jasmine/jasmine/blob/7f8f2b5e7a7af70d7f6b629331eb6fe0a7cb9279/src/core/requireInterface.js#L199

    使用 jasmine 2.6.1 回答原始问题,您将:

    var o = { get foo() {} };
    spyOnProperty(o, 'foo', 'get').and.returnValue('bar');
    

    【讨论】:

    • 这很有帮助,但我认为您的意思是“spyOnProperty”,而不是“spyOnAttribute”,对吗?
    • 明确。除了最后一行,我在其他任何地方都写了 spyOnProperty。我更新了答案。谢谢!
    【解决方案5】:

    如果您无法使用最新的茉莉花(2.6.1),您可以这样做

    const getSpy = jasmine.createSpy().and.returnValue('bar')
    Object.defineProperty(o, 'foo', { get: getSpy });
    

    defineProperty 的文档,here

    【讨论】:

    • 此解决方案适用于类上具有未初始化属性的情况(例如CognitoAuth'suserhandler property。在这种情况下,当您在控制台中检查对象时,您将不会拥有属性(在这种情况下为用户处理程序)。答案中排序的默认初始化有助于在稍后发生实际分配时监视属性。
    • 太棒了! :)
    【解决方案6】:

    我认为最好的方法是使用spyOnProperty。它需要 3 个属性,您需要将 getset 作为第三个属性传递。

    spyOnProperty(o, 'foo', 'get').and.returnValue('bar');
    

    【讨论】:

      猜你喜欢
      • 2014-01-19
      • 2020-07-16
      • 2013-11-07
      • 2020-04-08
      • 2013-01-09
      • 2017-06-16
      • 2015-02-17
      • 1970-01-01
      相关资源
      最近更新 更多