2016-07-29 36 views
1

Ich versuche gerade, eine React-Komponente zu testen und habe etwas Verwirrung über die Funktionen der Hilfsfunktionen gespottet. Das Modul sieht so etwas wie dieseVerwechslung mit mysteriösen zustandslosen Komponenten-Hilfsfunktionen mit sinon-, enyzme- und ES6-Importen

export const someHelper =() => { 
    return (<div></div>) 
} 

const MyComponent =() => { 
    return (
    <span> 
     {someHelper()} 
    </span> 
) 
} 
export default MyComponent 

und dann ist es das, was die Testdatei

import chai, { expect } from 'chai' 
import chaiEnzyme from 'chai-enzyme' 
import sinon from 'sinon' 
import { shallow } from 'enzyme' 
import React from 'react' 

import MyComponent, { someHelper } from './MyComponent' 

describe('MyComponent test', function(){ 
    it.only('should call someHelper once', function() { 
    let spy = sinon.spy(someHelper) 
    let myComponent = shallow(
     <MyComponent /> 
    ) 
    expect(spy.callCount).to.equal(1) 
    }) 
}) 

Dieser Test jedoch nicht als Callcount gleich 0 ist wie

sieht dachte ich, dass vielleicht hatte es etwas mit dem zu tun, Rahmen der someHelper Funktion, so dass ich diese Änderungen

export const helpers = { 
    someHelper() { 
    ... 
    } 
} 
const MyComponent =() => { 
    ... 
    {helpers.someHelper()} 
    ... 
} 

_

import MyComponent, { helpers } ... 

describe(...{ 
    it(...{ 
    let spy = sinon.spy(helpers.someHelper) 
    ... 
    }) 
}) 

Aber dieser Test nicht besteht nach wie vor mit 0 Callcount gleich habe ich dann diese Änderungen

describe(...{ 
    it(...{ 
    let spy = sinon.spy(helpers, 'someHelper') 
    ... 
    }) 
}) 

Und dann Test jetzt passiert.

Warum muss ich someHelper an das Objekt helpers anfügen, damit dieser Test funktioniert? Und warum muss ich die letzte spy(object, 'myfunc') Methode verwenden, wenn die sinon docs eine spy(myFunc) Option anzeigen?

Antwort

3

Warum muss ich someHelper an das Objekt helpers anfügen, damit dieser Test funktioniert?

Sinon muss in der Lage den Verweis auf die bestehende Funktion mit einem Spion/Stub-wrapped Version zu ersetzen, und es kann nur so tun, wenn das Referenz in einem Objekt (helpers in diesem Fall) gespeichert ist, .

Es tut im Grunde diese:

let functionToSpyOn = helpers.someHelper; 
let spy = sinon.spy(functionToSpyOn); 
helpers.someHelper = spy; 

Die zusätzliche Komplikation ist, dass die Original-Code die Funktion durch diesen Verweis aufrufen hat, so etwas wie dies funktionieren wird, auch nicht:

const someHelper  =() => { ... } 
export const helpers = { someHelper } 
const MyComponent =() => { 
    ... 
    {someHelper()} 
    ... 
} 

Der Grund dafür ist, dass MyComponent nicht die Referenz verwendet, die in helpers gespeichert ist. Diese Referenz wird von Sinon ersetzt. Deshalb muss die Komponente helpers.someHelper() verwenden.

Und warum muß ich die letzte spy(object, 'myfunc') Methode verwenden ...

Dies wiederum mit dem Ersetzen der Funktion mit einer eingewickelt Version davon zu tun hat.

... wenn die sinon docs eine spy(myFunc) Option anzeigen?

Ich finde, dass dieses Idiom im Allgemeinen von begrenzter Verwendung ist.Es sperrt nicht, wie Sie vielleicht denken, alle Anrufe zu myFunc, es sei denn, diese Anrufe werden auf das Spion-Objekt, das das Ergebnis von spy() ist, gemacht.

Zum Beispiel:

let callback = (err, result) => { ... } 
... 
let spy = sinon.spy(callback); 
someFuncToTest(spy); 
expect(spy.callCount).to.equal(1); 

Anstatt also die Callback-Funktion vorbei direkt, wird der Spion weitergegeben.

+0

Große Antwort, danke! Würde es also wirklich keine Möglichkeit geben, eine Funktion zu stubben, die direkt und nicht durch ein Objekt (d. H. Helfer) aufgerufen wird? – Weston

+1

@Weston nicht mit Sinon direkt, aber ['rewire'] (https://github.com/jhnns/rewire) und [' babel-plugin-rewire'] (https://github.com/speedskater/babel- plugin-rewire) kann dir vielleicht helfen (ersteres wahrscheinlich nicht so sehr, weil es bei Babel nicht funktioniert). – robertklep

1

Das Problem ist nicht spezifisch für React oder Sinon, sondern für JS im Allgemeinen.

Wenn so etwas passiert

var spiedMethod = (...args) => { 
    console.log('spy!'); 
    return object.method(...args); 
}; 

damit eine neue Funktion, die nicht die ursprüngliche object Methode ersetzt. Wenn object.method aufgerufen wird, wird spiedMethod nicht aufgerufen - die ursprüngliche Methode wird sein. Um sie zu ersetzen auf object, sollte das Objekt geändert werden:

object.method = spiedMethod; 

Das ist genau das, was Sinon Spione tun.

let spy = sinon.spy(myFunc); 

gibt sinon.spy(myFunc) einen Spion für die angegebene Funktion zurück. Damit der Anruf ausspioniert wird, sollte spy statt myFunc aufgerufen werden.

Es sei denn, etwas getan wird

helpers.someHelper = sinon.spy(helpers.someHelper); 

gibt es keine Möglichkeit, wie Sinon spy Funktion mit ausspioniert Methode zuordnen können. Dies ist, wo

sinon.spy(helpers, 'someHelper') 

kommt zur Rettung. Es tut im Wesentlichen helpers.someHelper = spy aber speichert auch die ursprüngliche Methode intern, also kann es helpers.someHelper = someHelperOriginal tun, wenn helpers.someHelper.restore() genannt wird.