So spionieren Sie mit Jasmine eine Werteigenschaft (anstelle einer Methode) aus

115

Jasmines spyOnist gut, um das Verhalten einer Methode zu ändern, aber gibt es eine Möglichkeit, eine Werteigenschaft (anstelle einer Methode) für ein Objekt zu ändern? Der Code könnte wie folgt aussehen:

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

Antworten:

97

Im Februar 2017 haben sie eine PR zusammengeführt und diese Funktion hinzugefügt, die sie im April 2017 veröffentlicht haben.

const spy = spyOnProperty(myObj, 'myGetterName', 'get'); Um Getter / Setter auszuspionieren, die Sie verwenden: Wenn myObj Ihre Instanz ist, ist 'myGetterName' der Name desjenigen, der in Ihrer Klasse als definiert ist, get myGetterName() {}und der dritte Parameter ist der Typ getoder set.

Sie können dieselben Behauptungen verwenden, die Sie bereits für die mit erstellten Spione verwenden spyOn.

So können Sie zum Beispiel:

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.

Hier ist die Zeile im Github-Quellcode, in der diese Methode verfügbar ist, wenn Sie interessiert sind.

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

Wenn Sie die ursprüngliche Frage mit Jasmin 2.6.1 beantworten, würden Sie:

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();
Juan
quelle
7
Wie mache ich das, wenn valueAein Observableoder ist Subject? Ich bekommeProperty valueA does not have access type get
Ka Mok
4
Das bedeutet wahrscheinlich, dass Sie es nicht für diese Eigenschaft verwenden können. spyOnProperty verwendet getOwnPropertyDescriptor und prüft, ob der Zugriffstyp get | set für diesen Eigenschaftsdeskriptor vorhanden ist. Der Fehler, den Sie erhalten, ist, dass der Eigenschaftsdeskriptor nicht festgelegt ist oder für die Eigenschaft abgerufen wird, die Sie ausspionieren möchten. Jasmine macht das: const descriptor = Object.getOwnPropertyDescriptor ... if (! Descriptor [accessType]) {// Fehler wird ausgelöst}
Juan
Es gibt also keine Möglichkeit, eine Eigenschaft ohne explizite Getter- und Setter-Methoden auszuspionieren? Spionieren ist eine Eigenschaft, die verwendet wird.
Dominik
@Dominik Hier habe ich alles, was damit zu tun hat,
Juan
1
@ Mathieu, es ist keine gute Behauptung, weil es nur behauptet, was wir bereits von dem wissen, was wir dem Spion gesagt haben, aber es ist genau das, was sie gefragt haben und ihr genaues Fragencode-Snippet ¯_ (ツ) _ / ¯ Der Punkt Ihre Frage war, wie man ein Grundstück ausspioniert und nicht so sehr ihr konkretes Beispiel.
Juan
12

Gibt es einen Grund, warum Sie es nicht einfach direkt am Objekt ändern können? Es ist nicht so, dass Javascript die Sichtbarkeit einer Eigenschaft für ein Objekt erzwingt.

Paul Harris
quelle
1
Die spyOnexplizite Verwendung bedeutet, dass ich etwas verspotten möchte, während die Eigenschaft implizit festgelegt wird, dass ich etwas verspotten möchte, und ich bin nicht sicher, ob jemand anderes verstehen wird, dass ich etwas verspotte, wenn er den Code liest. Ein anderer Fall ist, dass ich das innere Verhalten des Objekts nicht ändern möchte. Wenn ich beispielsweise die Längeneigenschaft für ein Array ändere, wird das Array
gekürzt
@Shuping, in diesem Fall würden Sie nicht verspotten. Sie würden stubben, was vollkommen in Ordnung ist. Sie würden das Verhalten nur innerhalb des Tests "ändern", was Sie mit dem erreichen wollten spyOn.
Fabio Milheiro
Möglicherweise möchten Sie den Prototyp des Laufzeitobjekts ausspionieren, um sicherzustellen, dass die Eigenschaft zur Laufzeit vorhanden ist. Jasmine besteht spyOnden Test nicht, wenn die Eigenschaft nicht vorhanden ist.
Sennett
2
Ein Beispiel ist das Setzen oder Löschen von window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
Chris Sattinger
2
Es ist nicht immer möglich, eine Objekteigenschaft in Javascript neu zuzuweisen
Renaud
12

Jasmine hat diese Funktionalität nicht, aber Sie können möglicherweise etwas zusammen hacken Object.defineProperty.

Sie können Ihren Code umgestalten, um eine Getter-Funktion zu verwenden, und dann den Getter ausspionieren.

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);
Eric
quelle
Ja, das kann ich jetzt tun.
Shuping
4
für Jasmin 2 ist es:and.returnValue(1)
Jtzero
9

Der beste Weg ist zu verwenden spyOnProperty. Es werden 3 Parameter erwartet und Sie müssen getoder setals dritten Parameter übergeben.

Beispiel

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

Hier setze ich das getof clientWidthdes div.nativeElementObjekts.

Aniruddha Das
quelle
6

Wenn Sie ES6 (Babel) oder TypeScript verwenden, können Sie die Eigenschaft mit get- und set-Accessoren löschen

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

Dann können Sie in Ihrem Test überprüfen, ob die Eigenschaft festgelegt ist mit:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');
Martin
quelle
Wenn die Getter Teil der zu testenden Klasse sind, können die Stubs in eine Unterklasse injiziert werden.
ccprog
6

Der richtige Weg, dies zu tun, ist mit der Eigenschaft spy on, mit der Sie eine Eigenschaft für ein Objekt mit einem bestimmten Wert simulieren können.

const spy = spyOnProperty(myObj, 'valueA').and.returnValue(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();
alexalejandroem
quelle
1

Angenommen, es gibt eine Methode wie diese, die getestet werden muss. Die srcEigenschaft des winzigen Bildes muss überprüft werden

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

Das folgende spyOn () bewirkt, dass dem "neuen Bild" der gefälschte Code aus dem Test zugeführt wird. Der spyOn-Code gibt ein Objekt zurück, das nur eine src-Eigenschaft hat

Da die Variable "hook" im gefälschten Code im SpyOn und auch später nach dem Aufruf von "reportABCEvent" sichtbar sein soll

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

Dies ist für Jasmin 1.3, funktioniert aber möglicherweise unter 2.0, wenn "andCallFake" in den Namen 2.0 geändert wird

Vorsprung
quelle
1

Ich verwende ein Kendo-Raster und kann daher die Implementierung nicht in eine Getter-Methode ändern, aber ich möchte dies testen (das Raster verspotten) und nicht das Raster selbst testen. Ich habe ein Spionageobjekt verwendet, aber dies unterstützt keine Eigenschaftsverspottung. Deshalb mache ich Folgendes:

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

Es ist ein bisschen langatmig, aber es funktioniert ein Vergnügen

jolySoft
quelle
0

Ich bin ein bisschen zu spät zur Party hier, ich weiß aber,

Sie können direkt auf das Aufrufobjekt zugreifen, das Ihnen die Variablen für jeden Aufruf gibt

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)
CosmicChild
quelle
-3

Sie können keine Variablen verspotten, aber Sie können eine Getter-Funktion dafür erstellen und diese Methode in Ihrer Spezifikationsdatei verspotten.

Gampesh
quelle