yasemin.createSpyObj özellikleriyle

Oct 28 2020

Açısal testlerimde bağımlılıkları alay ederken, genellikle şunu kullanarak bir casus nesne oluşturuyorum jasmine.createSpyObj:

const serviceSpy= jasmine.createSpyObj('MyService', ['method']);

daha sonra bunu TestBed'e sağlayın:

  providers: [
    {provide: MyService, useValue: serviceSpy}
  ]

Bunu testimde kullandığımda, daha sonra istenen dönüş değerini belirtebilirim:

serviceSpy.method.and.returnValue(of([...]));

Şimdi mülklerle dalga geçmem gerekiyor ve nasıl yapılması gerektiğini bulamıyorum. createSpyObjmülkiyet adlarının tanımlanmasına izin veriyor mu:

const serviceSpy= jasmine.createSpyObj('MyService', ['method'], ['property']);

ancak denedim, çok sayıda makaleye ve yanıtlara göre değişen çözümler ve başarı olmadan, örneğin:

// Cannot read property 'and' of undefined    
serviceSpy.property.and.returnValue(true);  
// not declared configurable
spyOnProperty(serviceSpy, 'property').and.returnValue(true);  
// no build errors, but value stays 'undefined'
serviceSpy.property = true;  

Bunu 'yarı' çalıştırabilmemin tek yolu şudur:

let fakeValue = true;
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], {'property': fakeValue});

Buradaki sorun, yaratılışta tek seferlik bir set olmasıdır. Testte beklenen değeri değiştirmek istersem işe yaramıyor.

fakeValue = false;
serviceSpy.property ==> stays to the initial value 'true';

Orada bir casus nesnesi oluşturarak sahte yöntemleri ve özellikleri için bir çözüm var, yoksa o zaman kullanabilirsiniz hangi kendi sahte sınıfı oluşturmak gerektiğini mu spyOnve spyOnProperty?

Tanımdaki özellikler dizisinin kullanımının ne olduğunu da bilmek istiyorum createSpyObj. Şimdiye kadar web'de bunu açıklayan herhangi bir örnek görmedim.

Yanıtlar

5 jonrsharpe Oct 28 2020 at 01:29

Başına belgelerinde (vurgu benim):

Üçüncü bir argüman olarak bir dizi veya özellik karması ileterek, üzerinde çeşitli özelliklere sahip bir casus nesnesi oluşturabilirsiniz createSpyObj. Bu durumda, oluşturulan casuslara bir referansınız olmayacak, bu yüzden casusluk stratejilerini daha sonra değiştirmeniz gerekirse, Object.getOwnPropertyDescriptoryaklaşımı kullanmanız gerekecektir .

it("creates a spy object with properties", function() {
  let obj = createSpyObj("myObject", {}, { x: 3, y: 4 });
  expect(obj.x).toEqual(3);

  Object.getOwnPropertyDescriptor(obj, "x").get.and.returnValue(7);
  expect(obj.x).toEqual(7);
});

Casus özellikler tanımlayıcılardır (örneğin Object.definePropertyMDN'ye bakın ), bu nedenle casus nesnelere erişmek için tanımlayıcı nesneyi almanız ve ardından üzerinde tanımlanan getve setyöntemleriyle etkileşimde bulunmanız gerekir .


TypeScript'te derleyicinin biraz yardıma ihtiyacı vardır. veya createSpyObjdöndürür ve a yalnızca yöntemleri casusluk olarak tanımlar :anySpyObj<T>SpyObj

type SpyObj<T> = T & {
    [K in keyof T]: T[K] extends Func ? T[K] & Spy<T[K]> : T[K];
               // |     if it's a     |    spy on it     | otherwise leave
               // |     callable      |                  | it alone
};

Yani erişim .andaçıklayıcısı en getter üzerine, ihtiyacınız opsiyonel zincirleme (olarak Object.getOwnPropertyDescriptormayıs dönüş undefined) ve bir tür iddiasını a Spy:

(Object.getOwnPropertyDescriptor(obj, "x")?.get as Spy<() => number>).and.returnValue(7);

Oyun alanı

1 IanGrainger Nov 11 2020 at 17:57

Çok teşekkür ederim @jonrsharpe! Sadece bir işlev ekledim, böylece yapabileyim:

spyPropertyGetter(spy, 'propName').and.returnValue(...)

Hangisi şu şekilde tanımlanır:

function spyPropertyGetter(
  spyObj: jasmine.SpyObj<any>,
  propName: string
) {
  return Object.getOwnPropertyDescriptor(spyObj, propName).get as jasmine.Spy<
    jasmine.Func
  >;
}