如何使用茉莉花监视值属性(而不是方法)


115

Jasmine的方法spyOn可以很好地改变方法的行为,但是有什么方法可以改变对象的value属性(而不是方法)?代码可能如下所示:

spyOn(myObj, 'valueA').andReturn(1);
expect(myObj.valueA).toBe(1);

Answers:


97

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

因此,您可以监视使用的getter / setter: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); 其中myObj是您的实例,“ myGetterName”是您的类中定义的那个的名称,get myGetterName() {}而第三个参数是type 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

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

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

7
如果valueAObservable或,我该怎么做Subject?我得到Property valueA does not have access type get
Ka Mok

4
这可能意味着您不能在该属性上使用它。spyOnProperty使用getOwnPropertyDescriptor并检查该属性描述符的访问类型get | set是否存在。您收到的错误是因为未设置属性描述符或获取了您要监视的属性。茉莉花这样做:const描述符= Object.getOwnPropertyDescriptor ... if(!descriptor [accessType]){//引发错误}
胡安

因此,没有显式的getter和setter方法就无法监视属性吗?监视是使用的属性。
多米尼克

@Dominik在这里,我写的所有的下一个较长的文章与此相关的引擎盖东西:medium.com/@juanlizarazo/...
胡安

1
@Mathieu并不是一个好的断言,因为它只是断言我们从告诉间谍该做的事情中已经知道了什么,但这只是他们在问的内容以及他们相同的问题代码段__(ツ)_ /¯他们的问题是如何监视财产,而不是他们的具体例子。
胡安

12

有什么原因不能直接在对象上更改它?这似乎不是javascript强制对象上属性的可见性。


1
spyOn显式使用表示我要模拟某些东西,而我直接设置该属性则隐式表示我要模拟某些东西,而且我不确定别人在阅读代码时是否会理解我在模拟某些东西。另一种情况是我不想更改对象的内部行为,例如,如果我更改数组的length属性,则会修剪数组,因此模拟会更好
Shuping 2014年

@Shuping,在这种情况下,您不会在嘲笑。你会打桩,这是完全可以的。您只会在测试中“改变行为”,而这正是您尝试通过来实现的spyOn
Fabio Milheiro 2014年

可能您想监视运行时对象原型,以确保该属性将在运行时存在。spyOn如果该属性不存在,Jasmine将无法通过测试。
sennett

2
一个示例是设置或删除window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
Chris Sattinger

2
并非总是可以在javascript中重新分配对象属性
Renaud

12

Jasmine没有该功能,但是您可以使用一起将某些东西砍在一起Object.defineProperty

您可以重构代码以使用getter函数,然后监视getter。

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);

是的,那是我现在可以做的。
舒平2014年

4
茉莉花2,它是:and.returnValue(1)
jtzero

9

最好的方法是使用spyOnProperty。它需要3个参数,您需要传递getset作为第三个参数。

const div = fixture.debugElement.query(By.css('.ellipsis-overflow'));
// now mock properties
spyOnProperty(div.nativeElement, 'clientWidth', 'get').and.returnValue(1400);
spyOnProperty(div.nativeElement, 'scrollWidth', 'get').and.returnValue(2400);

在这里,我设置getclientWidthdiv.nativeElement对象。


6

如果您使用的是ES6(Babel)或TypeScript,则可以使用get和set访问器对属性进行存根

export class SomeClassStub {
  getValueA = jasmine.createSpy('getValueA');
  setValueA = jasmine.createSpy('setValueA');
  get valueA() { return this.getValueA(); }
  set valueA(value) { this.setValueA(value); }
}

然后,在测试中,您可以检查属性是否设置为:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');

或者,如果吸气剂属于被测类的一部分,则可以将存根插入子类中。
ccprog

6

正确的方法是使用spy on属性,它将使您可以模拟具有特定值的对象的属性。

const spy = spyOnProperty(myObj, 'valueA').and.returnValue(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

1

假设有一个需要测试的src方法,微小图像的属性需要检查

function reportABCEvent(cat, type, val) {
                var i1 = new Image(1, 1);
                var link = getABC('creosote');
                    link += "&category=" + String(cat);
                    link += "&event_type=" + String(type);
                    link += "&event_value=" + String(val);
                    i1.src = link;
                }

下面的spyOn()导致“新图像”被送入来自测试的伪代码,spyOn代码返回仅具有src属性的对象

由于变量“ hook”的作用域在SpyOn中的伪代码中可见,并且稍后在调用“ reportABCEvent”之后也可见

describe("Alphabetic.ads", function() {
    it("ABC events create an image request", function() {
    var hook={};
    spyOn(window, 'Image').andCallFake( function(x,y) {
          hook={ src: {} }
          return hook;
      }
      );
      reportABCEvent('testa', 'testb', 'testc');
      expect(hook.src).
      toEqual('[zubzub]&arg1=testa&arg2=testb&event_value=testc');
    });

这适用于茉莉花1.3,但如果将“ andCallFake”更改为2.0名称,则可能适用于2.0


1

我使用的是Kendo网格,因此无法将实现更改为getter方法,但我想对此进行测试(模拟网格),而不测试网格本身。我使用的是间谍对象,但这不支持属性模拟,因此我这样做:

    this.$scope.ticketsGrid = { 
        showColumn: jasmine.createSpy('showColumn'),
        hideColumn: jasmine.createSpy('hideColumn'),
        select: jasmine.createSpy('select'),
        dataItem: jasmine.createSpy('dataItem'),
        _data: []
    } 

有点长但是可以治疗


0

我在这里参加聚会有点晚了,但是,

您可以直接访问电话对象,该对象可以为您提供每个电话的变量

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)

-3

您不能模拟变量,但是可以为其创建getter函数,并在spec文件中模拟该方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.