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

匿名 (未验证) 提交于 2019-12-03 01:12:01

问题:

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:

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


回答5:

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



回答6:

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



回答7:

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) 


回答8:

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

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.



回答9:

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



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