Cómo espiar una propiedad de valor (en lugar de un método) con Jasmine

115

Jasmine spyOnes bueno para cambiar el comportamiento de un método, pero ¿hay alguna forma de cambiar una propiedad de valor (en lugar de un método) para un objeto? el código podría ser el siguiente:

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

Respuestas:

97

En febrero de 2017, fusionaron un PR agregando esta función, que lanzaron en abril de 2017.

así que para espiar los getters / setters que usa: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); donde myObj es su instancia, 'myGetterName' es el nombre del que está definido en su clase como get myGetterName() {}y el tercer parámetro es el tipo geto set.

Puede usar las mismas afirmaciones que ya usa con los espías creados con spyOn.

Entonces puedes, por ejemplo:

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.

Aquí está la línea en el código fuente de github donde este método está disponible si está interesado.

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

Respondiendo a la pregunta original, con jazmín 2.6.1, haría lo siguiente:

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();
Juan
fuente
7
¿Cómo hago esto si valueAes un Observableo Subject? Estoy recibiendoProperty valueA does not have access type get
Ka Mok
4
Eso probablemente significa que no puede usarlo en esa propiedad. spyOnProperty usa getOwnPropertyDescriptor y verifica si el tipo de acceso get | set para ese descriptor de propiedad existe. El error que está recibiendo es porque el descriptor de propiedad no está establecido o no se obtiene para la propiedad que está tratando de espiar. Jasmine hace esto: const descriptor = Object.getOwnPropertyDescriptor ... if (! Descriptor [accessType]) {// se produce un error}
Juan
Entonces, ¿no hay forma de espiar una propiedad sin métodos explícitos getter y setter? Espiar es una propiedad utilizada.
Dominik
@Dominik Aquí escribí todo lo relacionado con esto en un artículo más largo: medium.com/@juanlizarazo/…
Juan
1
@Mathieu no es una buena afirmación porque solo afirma lo que ya sabemos por lo que le dijimos al espía que hiciera, pero es solo lo que estaban preguntando y su mismo fragmento de código de pregunta ¯_ (ツ) _ / ¯ El punto su pregunta era cómo espiar una propiedad y no tanto su ejemplo específico.
Juan
12

¿Alguna razón por la que no puede cambiarlo directamente en el objeto? No es como si JavaScript imponga la visibilidad de una propiedad en un objeto.

Paul Harris
fuente
1
el uso spyOnindica explícitamente que quiero simular algo, mientras que establezco directamente la propiedad indica implícitamente que quiero simular algo, y no estoy seguro de que alguien más entienda que me estoy burlando de algo cuando él está leyendo el código. El otro caso es que no quiero cambiar el comportamiento interno del objeto, por ejemplo, si cambio la propiedad de longitud de una matriz, la matriz se recorta, por lo que una simulación será mejor
Shuping
@Shuping, en este caso, no te estarías burlando. Estarías tropezando, lo cual está perfectamente bien. Estaría "cambiando el comportamiento" solo dentro de la prueba, que es lo que estaba tratando de lograr con spyOn.
Fabio Milheiro
Posiblemente desee espiar el prototipo del objeto en tiempo de ejecución para asegurarse de que la propiedad existirá en el tiempo de ejecución. Jasmine spyOnno pasa la prueba si la propiedad no existe.
sennett
2
Un ejemplo es configurar o eliminar window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
Chris Sattinger
2
No siempre es posible reasignar una propiedad de objeto en javascript
Renaud
12

Jasmine no tiene esa funcionalidad, pero es posible que puedas hackear algo juntos usando Object.defineProperty.

Puede refactorizar su código para usar una función de captador, luego espiar el captador.

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);
Eric
fuente
Sí, eso es lo que puedo hacer por ahora.
Shuping el
4
para jazmín 2 es:and.returnValue(1)
jtzero
9

La mejor forma es utilizar spyOnProperty. Espera 3 parámetros y debe pasar geto setcomo tercer parámetro .

Ejemplo

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

Aquí estoy fijando la getde clientWidthdel div.nativeElementobjeto.

Aniruddha Das
fuente
6

Si está utilizando ES6 (Babel) o TypeScript, puede eliminar la propiedad utilizando los accesos get y set

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

Luego, en su prueba, puede verificar que la propiedad esté configurada con:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');
Martín
fuente
O, si los getters son parte de la clase bajo prueba, los stubs podrían inyectarse en una subclase.
ccprog
6

La forma correcta de hacer esto es con la propiedad de espiar, que le permitirá simular una propiedad en un objeto con un valor específico.

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

Supongamos que hay un método como este que necesita ser probado. La srcpropiedad de la imagen diminuta necesita ser revisada.

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

El spyOn () a continuación hace que la "nueva imagen" se alimente con el código falso de la prueba. El código spyOn devuelve un objeto que solo tiene una propiedad src.

Como la variable "gancho" tiene como alcance para ser visible en el código falso en el SpyOn y también más adelante después de que se llama "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');
    });

Esto es para jasmine 1.3 pero podría funcionar en 2.0 si "andCallFake" se modifica por el nombre 2.0

Vorsprung
fuente
1

Estoy usando una cuadrícula de kendo y, por lo tanto, no puedo cambiar la implementación a un método getter, pero quiero probar esto (burlándome de la cuadrícula) y no probar la cuadrícula en sí. Estaba usando un objeto espía pero esto no es compatible con la burla de propiedad, así que hago esto:

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

Es un poco largo pero funciona de maravilla

jolySoft
fuente
0

Llego un poco tarde a la fiesta, lo sé, pero

Puede acceder directamente al objeto de llamadas, que puede proporcionarle las variables para cada llamada

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

No puede simular la variable, pero puede crear una función getter para ella y simular ese método en su archivo de especificaciones.

Gampesh
fuente