Comment espionner une propriété de valeur (plutôt qu'une méthode) avec Jasmine

115

Jasmine spyOnest bon pour changer le comportement d'une méthode, mais y a-t-il un moyen de changer une propriété de valeur (plutôt qu'une méthode) pour un objet? le code pourrait être comme ci-dessous:

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

Réponses:

97

En février 2017, ils ont fusionné un PR en ajoutant cette fonctionnalité, ils ont publié en avril 2017.

donc pour espionner les getters / setters que vous utilisez: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); où myObj est votre instance, 'myGetterName' est le nom de celui défini dans votre classe as get myGetterName() {}et le troisième paramètre est le type getou set.

Vous pouvez utiliser les mêmes affirmations que vous utilisez déjà avec les espions créés avec spyOn.

Ainsi, vous pouvez par exemple:

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.

Voici la ligne du code source github où cette méthode est disponible si vous êtes intéressé.

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

En répondant à la question initiale, avec jasmine 2.6.1, vous:

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();
Juan
la source
7
Comment faire cela si valueAest un Observableou Subject? Je reçoisProperty valueA does not have access type get
Ka Mok
4
Cela signifie probablement que vous ne pouvez pas l'utiliser sur cette propriété. spyOnProperty utilise getOwnPropertyDescriptor et vérifie si le type d'accès get | set pour ce descripteur de propriété existe. L'erreur que vous obtenez est que le descripteur de propriété n'est pas défini ou obtenu pour la propriété que vous essayez d'espionner. Jasmine fait ceci: const descriptor = Object.getOwnPropertyDescriptor ... if (! Descriptor [accessType]) {// une erreur est lancée}
Juan
Donc, il n'y a aucun moyen d'espionner une propriété sans méthodes explicites getter et setter? Espionner est une propriété utilisée.
Dominik le
@Dominik Ici, j'ai écrit tous les trucs sous le capot liés à cela dans un article plus long: medium.com/@juanlizarazo
Juan
1
@Mathieu ce n'est pas une bonne assertion car elle affirme simplement ce que nous savons déjà de ce que nous avons dit à l'espion de faire, mais c'est juste ce qu'ils demandaient et leur même extrait de code de question ¯_ (ツ) _ / ¯ Le point de leur question était de savoir comment espionner une propriété et pas tellement leur exemple spécifique.
Juan le
12

Une raison pour laquelle vous ne pouvez pas simplement le modifier directement sur l'objet? Ce n'est pas comme si javascript imposait la visibilité d'une propriété sur un objet.

Paul Harris
la source
1
l'utilisation spyOnindique explicitement que je veux moquer quelque chose, alors que je définis directement la propriété indique implicitement que je veux moquer quelque chose, et je ne suis pas sûr que quelqu'un d'autre comprendra que je me moque de quelque chose quand il lit le code. Un autre cas est que je ne veux pas changer le comportement interne de l'objet, par exemple si je change la propriété de longueur pour un tableau, le tableau est coupé, donc une maquette sera meilleure
Shuping
@Shuping, dans ce cas, vous ne vous moqueriez pas. Vous seriez stubbing, ce qui est parfaitement normal. Vous ne «changeriez le comportement» que dans le test, ce que vous essayez d’obtenir avec le spyOn.
Fabio Milheiro
Vous souhaitez peut-être espionner le prototype d'objet d'exécution pour vous assurer que la propriété existera au moment de l'exécution. Jasmine spyOnéchoue au test si la propriété n'existe pas.
sennett
2
Un exemple consiste à définir ou supprimer window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
Chris Sattinger
2
Il n'est pas toujours possible de réaffecter une propriété d'objet en javascript
Renaud
12

Jasmine n'a pas cette fonctionnalité, mais vous pourrez peut-être pirater quelque chose ensemble en utilisant Object.defineProperty.

Vous pouvez refactoriser votre code pour utiliser une fonction getter, puis espionner le getter.

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);
Eric
la source
Oui, c'est ce que je peux faire pour le moment.
Shuping le
4
pour jasmine 2 c'est:and.returnValue(1)
jtzero
9

Le meilleur moyen est d'utiliser spyOnProperty. Il attend 3 paramètres et vous devez passer getou setcomme troisième paramètre .

Exemple

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

Ici , je suis en train de l' getde clientWidthd' div.nativeElementobjet.

Aniruddha Das
la source
6

Si vous utilisez ES6 (Babel) ou TypeScript, vous pouvez extraire la propriété à l'aide des accesseurs get et set

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

Ensuite, dans votre test, vous pouvez vérifier que la propriété est définie avec:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');
Martin
la source
Ou, si les getters font partie de la classe testée, les stubs pourraient être injectés dans une sous-classe.
ccprog
6

La bonne façon de faire est avec la propriété d'espionnage, elle vous permettra de simuler une propriété sur un objet avec une valeur spécifique.

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

Supposons qu'il existe une méthode comme celle-ci qui doit être testée La srcpropriété de la petite image doit être vérifiée

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

Le spyOn () ci-dessous fait que la "nouvelle image" reçoit le faux code du test le code spyOn renvoie un objet qui n'a qu'une propriété src

Comme la variable "hook" est censée être visible dans le faux code dans SpyOn et aussi plus tard après l'appel de "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');
    });

Ceci est pour jasmine 1.3 mais pourrait fonctionner sur 2.0 si le "andCallFake" est modifié pour le nom 2.0

Vorsprung
la source
1

J'utilise une grille de kendo et je ne peux donc pas changer l'implémentation en une méthode getter mais je veux tester autour de cela (se moquer de la grille) et ne pas tester la grille elle-même. J'utilisais un objet espion mais cela ne prend pas en charge la moquerie de propriété, alors je fais ceci:

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

C'est un peu long mais ça marche un régal

jolySoft
la source
0

Je suis un peu en retard à la fête ici je sais mais,

Vous pouvez accéder directement à l'objet des appels, qui peut vous donner les variables pour chaque appel

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)
CosmicEnfant
la source
-3

Vous ne pouvez pas simuler une variable, mais vous pouvez créer une fonction getter pour elle et simuler cette méthode dans votre fichier de spécifications.

Gampesh
la source