2015-10-15 4 views
29

Wie kann ich eine Getter-Eigenschaft mit Jasmin ausspionieren?Wie kann ich eine Getter-Eigenschaft mit Jasmin ausspionieren?

var o = { get foo() {}, }; 

spyOn(o, 'foo').and.returnValue('bar'); // Doesn't work. 

Dies auch nicht funktioniert AFAICT:

spyOn(Object.getOwnPropertyDescriptor(o, 'foo'), 'get').and.returnValue('bar'); 
+0

Aus der Diskussion über [diese ähnliche Frage] (http://stackoverflow.com/questions/31338197) können Sie nicht. Getter und Setter werden nicht als Standardmethoden behandelt (sie müssen z. B. nicht als Funktionen aufgerufen werden). – Mathletics

+0

Vielleicht könnten Sie einfach ein Ergebnis des abgerufenen Werts in Abhängigkeit von verschiedenen Objektzuständen testen. –

+1

Basierend auf den Kommentaren, ist es anscheinend nicht implementiert, aber es ist theoretisch nicht unmöglich. Der Grund 'spyOn (Object.getOwnPropertyDescriptor (o,' foo '),' get ') 'funktioniert nicht, weil' spyOn' die Eigenschaft des Objekts als eine neue Funktion schreibt, die die existierende Funktion umschließt. Das Ändern des Eigenschaftsdeskriptorobjekts, das von 'getOwnPropertyDescriptor' zurückgegeben wird, ändert nichts an der tatsächlichen Eigenschaft. Sie könnten jedoch Jasmine ändern, um Setter/Getter zu erkennen und die Eigenschaft mit 'defineProperty' neu schreiben. Vielleicht eine Feature-Anfrage öffnen, wenn es dir wichtig ist? – apsillers

Antwort

19

Seit Jasmin 2.6, dies mit spyOnProperty möglich gewesen. Auszuspionieren auf den Zugriffs- für die foo Sach tun:

spyOnProperty(o, 'foo') 

Auf diese Weise können Sie die set und/oder get Accessorfunktionen für eine Accessor-Eigenschaft mit einem Spion-Funktion ersetzen. Sie können nur als drittes Argument angeben oder set oder get:

spyOnProperty(o, 'foo', 'get') 

Wenn Sie eine frühere Version stecken verwenden und kann aus irgendeinem Grund nicht aktualisieren, können Sie die pull request that added this feature in die lokale Kopie des Codes der Lage sein, zu fusionieren .

+1

Habe ich richtig gedacht, dass dies fehlschlägt, wenn der 'accessor' nicht als' konfigurierbar: true' eingestellt wurde? Was bedeutet, dass Sie kein Glück haben, wenn Sie versuchen, einen Drittanbieter-Accessor auszuspionieren, wo dies nicht angegeben ist? – james

+0

@james Ich denke, dass eine nicht konfigurierbare Eigenschaft (ob Accessor-basiert oder eine traditionelle Dateneigenschaft) von Jasmine nie ausspioniert werden kann. (Ich bin nicht 100% und kann im Moment nicht testen, aber alle Spionage basiert auf Ersatz von Eigentum.) – apsillers

0

Ich glaube nicht, Sie auf Getter ausspionieren. Der Sinn eines Getters ist, dass er genau wie eine Eigenschaft wirkt, also wie kann Jasmin es ausspionieren, wenn es nie wie eine Funktion aufgerufen wird, sondern wie eine Eigenschaft aufgerufen wird.

Um dieses Problem zu umgehen, können Sie Ihren Getter eine andere Funktion aufrufen lassen und stattdessen diese ausspionieren.

var o = { 
    _foo: function(){ 
     return 'foo'; 
    }, 
    get foo(){ 
     return this._foo(); 
    } 
}; 

spyOn(o, '_foo').and.returnValue('bar'); 
5

nahm ich Inspiration aus @apsillers Antwort und schrieb den folgenden Helfer (erfordert die prop konfigurierbar zu sein, wie oben erwähnt)

let activeSpies = []; 
let handlerInstalled = false; 

function afterHandler() { 
    activeSpies.forEach(({ obj, prop, descriptor }) => Object.defineProperty(obj, prop, descriptor)); 
    activeSpies = []; 
} 


export function spyOnGetter(obj, prop) { 
    const env = jasmine.getEnv(); 
    const descriptor = Object.getOwnPropertyDescriptor(obj, prop); 
    const spy = jasmine.createSpy(`${prop} spy`); 
    const copy = Object.assign({}, descriptor, { get: spy }); 
    Object.defineProperty(obj, prop, copy); 
    activeSpies.push({ 
     obj, 
     prop, 
     descriptor, 
    }); 

    if (!handlerInstalled) { 
     handlerInstalled = true; 
     env.afterEach(() => afterHandler()); 
    } 
    return spy; 
} 

Und es kann wie so verwendet werden:

import { spyOnGetter } from spyExtra; 
it('tests the thing',() => { 
    spyOnGetter(myObj, 'myProp').and.returnValue(42); 
    expect(myObj.myProp).toBe(42); 
}); 

Hoffnung es ist nützlich!

19

Im Februar 2017 sie eine PR Hinzufügen dieser Funktion zusammen veröffentlichten sie es im April 2017.

so auf Getter auszuspionieren/Setter Sie verwenden: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); wo myObj Instanz ist, ‚myGetterName‘ ist der Name des in Ihrer Klasse als get myGetterName() {} definierten Parameters und der dritte Parameter ist der Typ get oder set.

Sie können dieselben Assertionen verwenden, die Sie bereits mit den mit spyOn erstellten Spionen verwenden.

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 Linie in der Github Quellcode, in dem diese Methode zur Verfügung, wenn Sie interessiert sind.

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

Beantwortung der ursprünglichen Frage, mit Jasmin 2.6.1, würden Sie:

var o = { get foo() {} }; 
spyOnProperty(o, 'foo', 'get').and.returnValue('bar'); 
+0

Das ist hilfreich, aber ich denke du meinst 'spyOnProperty', nicht 'spyOnAttribute', korrekt? – kpup

+0

Definitiv. Ich habe spyOnProperty überall außer der letzten Zeile geschrieben. Ich habe die Antwort aktualisiert. Vielen Dank! – Juan

0

Sie können dies tun, wenn Sie nicht die neueste Jasmin (2.6.1) für DefineProperty

const getSpy = jasmine.createSpy().and.returnValue('bar') 
Object.defineProperty(o, 'foo', { get: getSpy }); 

Dokumentation verwenden, here

3

Ich denke, die beste Weg ist zu verwenden spyOnProperty. Es erwartet 3 Eigenschaften und Sie müssen get oder set als dritte Eigenschaft übergeben.

spyOnProperty(o, 'foo', 'get').and.returnValue('bar'); 
Verwandte Themen