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


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.