How to spyOn a value property (rather than a method) with Jasmine

前端 未结 10 2211
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-01 04:12

Jasmine\'s spyOn is good to change a method\'s behavior, but is there any way to change a value property (rather than a method) for an object? the code could be

相关标签:
10条回答
  • 2020-12-01 04:24

    The best way is to use spyOnProperty. It expects 3 parameters and you need to pass get or set as a third param.

    Example

    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);
    

    Here I am setting the get of clientWidth of div.nativeElement object.

    0 讨论(0)
  • 2020-12-01 04:29

    If you are using ES6 (Babel) or TypeScript you can stub out the property using get and set accessors

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

    Then in your test you can check that the property is set with:

    stub.valueA = 'foo';
    
    expect(stub.setValueA).toHaveBeenCalledWith('foo');
    
    0 讨论(0)
  • 2020-12-01 04:30

    The right way to do this is with the spy on property, it will allow you to simulate a property on an object with an specific value.

    const spy = spyOnProperty(myObj, 'valueA').and.returnValue(1);
    expect(myObj.valueA).toBe(1);
    expect(spy).toHaveBeenCalled();
    
    0 讨论(0)
  • 2020-12-01 04:35

    In February 2017, they merged a PR adding this feature, they released in April 2017.

    so to spy on getters/setters you use: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); where myObj is your instance, 'myGetterName' is the name of that one defined in your class as get myGetterName() {} and the third param is the type get or set.

    You can use the same assertions that you already use with the spies created with spyOn.

    So you can for example:

    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.
    

    Here's the line in the github source code where this method is available if you are interested.

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

    Answering the original question, with jasmine 2.6.1, you would:

    const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
    expect(myObj.valueA).toBe(1);
    expect(spy).toHaveBeenCalled();
    
    0 讨论(0)
  • 2020-12-01 04:35

    Any reason you cannot just change it on the object directly? It is not as if javascript enforces visibility of a property on an object.

    0 讨论(0)
  • 2020-12-01 04:39

    I'm using a kendo grid and therefore can't change the implementation to a getter method but I want to test around this (mocking the grid) and not test the grid itself. I was using a spy object but this doesn't support property mocking so I do this:

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

    It's a bit long winded but it works a treat

    0 讨论(0)
提交回复
热议问题