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

我的未来我决定 提交于 2019-12-17 10:33:26

问题


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 like below:

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

回答1:


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



回答2:


Jasmine doesn't have that functionality, but you might be able to hack something together using Object.defineProperty.

You could refactor your code to use a getter function, then spy on the getter.

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



回答3:


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.




回答4:


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.




回答5:


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



回答6:


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



回答7:


Suppose there is a method like this that needs testing The src property of the tiny image needs checking

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

The spyOn() below causes the "new Image" to be fed the fake code from the test the spyOn code returns an object that only has a src property

As the variable "hook" is scoped to be visible in the fake code in the SpyOn and also later after the "reportABCEvent" is called

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

This is for jasmine 1.3 but might work on 2.0 if the "andCallFake" is altered to the 2.0 name




回答8:


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




回答9:


I'm a bit late to the party here i know but,

You could directly access the calls object, which can give you the variables for each call

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



回答10:


You can not mock variable but you can create getter function for it and mock that method in your spec file.



来源:https://stackoverflow.com/questions/20879990/how-to-spyon-a-value-property-rather-than-a-method-with-jasmine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!