Como espionar em uma propriedade de valor (em vez de um método) com Jasmine


115

O Jasmine's spyOné bom para mudar o comportamento de um método, mas existe alguma maneira de mudar uma propriedade de valor (ao invés de um método) para um objeto? o código pode ser como abaixo:

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

Respostas:


97

Em fevereiro de 2017, eles mesclaram um PR adicionando esse recurso, lançado em abril de 2017.

então, para espionar getters / setters que você usa: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); onde myObj é sua instância, 'myGetterName' é o nome daquele definido em sua classe como get myGetterName() {}e o terceiro parâmetro é o tipo getou set.

Você pode usar as mesmas afirmações que já usa com os espiões criados com spyOn.

Então você pode, por exemplo:

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.

Esta é a linha no código-fonte do github onde esse método está disponível, se você estiver interessado.

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

Respondendo à pergunta original, com o jasmine 2.6.1, você:

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

7
Como faço isso se valueAfor um Observableou Subject? Estou recebendoProperty valueA does not have access type get
— Ka Mok

4
Isso provavelmente significa que você não pode usá-lo nessa propriedade. spyOnProperty está usando getOwnPropertyDescriptor e verificando se o tipo de acesso get | set para esse descritor de propriedade existe. O erro que você está recebendo é porque o descritor de propriedade não foi definido ou obtido para a propriedade que você está tentando espionar. Jasmine faz isso: const descriptor = Object.getOwnPropertyDescriptor ... if (! Descriptor [accessType]) {// o erro é gerado}
— Juan

Portanto, não há como espionar uma propriedade sem os métodos getter e setter explícitos? Espiar é uma propriedade usada.
— Dominik

@Dominik Aqui eu escrevi todas as coisas subjacentes
— Juan

1
@Mathieu não é uma boa afirmação porque apenas afirma o que já sabemos do que dissemos ao espião para fazer, mas é apenas o que eles estavam perguntando e seu mesmo trecho de código de pergunta ¯_ (ツ) _ / ¯ O ponto de sua questão era como espionar uma propriedade e não tanto seu exemplo específico.
— Juan

12

Alguma razão pela qual você não pode simplesmente alterá-lo no objeto diretamente? Não é como se o javascript reforçasse a visibilidade de uma propriedade em um objeto.


1
usar spyOnexplicitamente indica que quero simular algo, enquanto defino diretamente a propriedade indica implicitamente que quero simular algo e não tenho certeza se alguém entenderá que estou zombando de algo quando estiver lendo o código. Outro caso é que eu não quero mudar o comportamento interno do objeto, por exemplo, se eu mudar a propriedade de comprimento de um array, o array é aparado, então uma simulação será melhor
— Shuping

@Shuping, neste caso, você não estaria zombando. Você estaria fazendo stub, o que é perfeitamente normal. Você estaria "mudando o comportamento" apenas dentro do teste, que é o que você estava tentando alcançar com o spyOn.
— Fabio Milheiro

Possivelmente, você deseja espionar o protótipo do objeto de tempo de execução para ter certeza de que a propriedade existirá no tempo de execução. Jasmine spyOnfalha no teste se a propriedade não existir.
— sennett,

2
Um exemplo é definir ou excluir window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
— Chris Sattinger

2
Nem sempre é possível reatribuir uma propriedade de objeto em javascript
— Renaud

12

Jasmine não tem essa funcionalidade, mas você pode conseguir hackear algo junto usando Object.defineProperty.

Você pode refatorar seu código para usar uma função getter e, em seguida, espionar o getter.

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);

Sim, é o que posso fazer por enquanto.
— Shuping

4
para jasmim 2 é:and.returnValue(1)
— jtzero

9

A melhor forma é usar spyOnProperty. Ele espera 3 parâmetros e você precisa passar getou setcomo um terceiro parâmetro.

Exemplo

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

Aqui eu estou definindo o getde clientWidthde div.nativeElementobjeto.


6

Se você estiver usando ES6 (Babel) ou TypeScript, você pode remover a propriedade usando os acessadores get e set

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

Então, em seu teste, você pode verificar se a propriedade está definida com:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');

Ou, se os getters fizerem parte da classe em teste, os stubs podem ser injetados em uma subclasse.
— ccprog

6

A maneira certa de fazer isso é com a propriedade do espião, que permitirá simular uma propriedade em um objeto com um valor específico.

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

1

Suponha que haja um método como este que precisa de teste A srcpropriedade da imagem minúscula precisa de verificação

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

O spyOn () abaixo faz com que a "nova imagem" seja alimentada com o código falso do teste o código spyOn retorna um objeto que tem apenas uma propriedade src

Como a variável "gancho" tem o escopo definido para ser visível no código falso no SpyOn e também mais tarde após o "reportABCEvent" ser chamado

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

Isso é para o jasmine 1.3, mas pode funcionar no 2.0 se "andCallFake" for alterado para o nome 2.0


1

Estou usando uma grade de kendo e, portanto, não posso alterar a implementação para um método getter, mas quero testar em torno disso (simulando a grade) e não testar a grade em si. Eu estava usando um objeto espião, mas ele não suporta simulação de propriedade, então faço o seguinte:

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

É um pouco prolixo, mas funciona muito bem


0

Estou um pouco atrasado para a festa aqui eu sei, mas,

Você pode acessar diretamente o objeto de chamadas, que pode fornecer as variáveis ​​para cada chamada

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)

-3

Você não pode simular uma variável, mas pode criar uma função getter para ela e simular esse método em seu arquivo de especificação.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.