Як шпигувати властивість значення (а не метод) за допомогою Жасмін


115

Жасмін spyOnкорисно змінити поведінку методу, але чи є спосіб змінити властивість значення (а не метод) для об'єкта? код може бути як нижче:

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

Відповіді:


97

У лютому 2017 року вони об'єднали PR, додавши цю функцію, вони вийшли у квітні 2017 року.

тому const spy = spyOnProperty(myObj, 'myGetterName', 'get'); шпигуйте за тим, хто ви використовуєте / встановлюєте: де myObj - ваш екземпляр, 'myGetterName' - це ім'я, визначене у вашому класі як, get myGetterName() {}а третій парам - тип getабо set.

Ви можете використовувати ті самі твердження, які ви вже використовуєте зі шпигунами, створеними разом із 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
Як це зробити, якщо valueAце Observableабо Subject? Я отримуюProperty valueA does not have access type get
— Ka Mok

4
Це, ймовірно, означає, що ви не можете використовувати його у цій власності. spyOnProperty використовує getOwnPropertyDescriptor і перевіряє, чи існує тип доступу get | встановлений для цього дескриптора властивості. Помилка, яку ви отримуєте, полягає в тому, що дескриптор властивості не встановлений або отримати для власності, яку ви намагаєтесь шпигувати. Жасмін робить це: const descriptor = Object.getOwnPropertyDescriptor ... якщо (! Дескриптор [accessType]) {// викидається помилка}
— Хуан

Отже, немає способу шпигувати за власністю без явних методів getter та setter? Шпигувати - це властивість.
— Домінік

@Dominik Тут я написав усі деталі під капотом, пов’язані з цим, у більш довгій статті: medium.com/@juanlizarazo/…
— Хуан

1
@Mathieu це не гарне твердження, тому що воно просто стверджує те, що ми вже знаємо з того, про що ми сказали шпигуну, але це саме те, що вони запитували, і їх самий фрагмент коду питання ¯_ (ツ) _ / ¯ Справа їх питання полягало в тому, як шпигувати за майном і не стільки їх конкретним прикладом.
— Хуан

12

З якої причини ви не можете просто змінити його на об'єкті безпосередньо? Це не так, як якщо JavaScript підтримує видимість властивості на об'єкті.


1
використання spyOnявно вказує на те, що я хочу щось знущатися, тоді як я безпосередньо встановлюю властивість неявно вказує на те, що я хочу щось знущатися, і я не впевнений, що хтось інший зрозуміє, що я щось знущаюся, коли він читає код. Інший випадок полягає в тому, що я не хочу змінювати внутрішню поведінку об'єкта, наприклад, якщо я зміню властивість довжини для масиву, масив обрізається, тому макет буде кращим
— Shuping

@Shuping, у цьому випадку ви не знущаєтесь. Ви б затхнули, що цілком нормально. Ви б "змінювали поведінку" лише всередині тесту, якого ви намагалися досягти spyOn.
— Фабіо Мілхейро

Можливо, ви хочете шпигувати за прототипом об’єкта виконання, щоб переконатися, що властивість буде існувати під час виконання. Жасмін spyOnпроходить тест, якщо властивості не існує.
— сеннетт

2
Один із прикладів - встановити або видалити window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
— Chris Sattinger

2
Не завжди можливо перепризначити властивість об’єкта у javascript
— Renaud

12

Жасмін не має такої функціональності, але ви, можливо, зможете щось зламати разом, використовуючи Object.defineProperty.

Ви можете перефактурувати свій код, щоб використовувати функцію геттера, а потім шпигувати за геттером.

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

Так, це я зараз можу зробити.
— Шупинг

4
для жасмину 2 це:and.returnValue(1)
— jtzero

9

Найкращий спосіб - використовувати spyOnProperty. Він очікує 3 параметра, і вам потрібно пройти getабо setяк третій парам.

Приклад

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

Тут я встановлюю getз clientWidthз div.nativeElementоб'єкта.


6

Якщо ви використовуєте ES6 (Babel) або TypeScript, ви можете заглушити властивість за допомогою 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); }
}

Потім у вашому тесті ви можете перевірити, чи встановлено властивість:

stub.valueA = 'foo';

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

Або, якщо геттери є частиною тестуваного класу, заглушки можуть бути введені в підклас.
— ccprog

6

Правильний спосіб зробити це зі шпигуном на власність, він дозволить вам імітувати властивість на об’єкті з конкретним значенням.

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

По мірі того, як змінна "гачок" визначається, видно у підробленому коді в 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, але він може працювати на версії 2.0, якщо "andCallFake" буде змінено на ім'я 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 для неї та знущатися над цим методом у вашому специфікаційному файлі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.