yasemin.createSpyObj özellikleriyle
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
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ı
Ç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
>;
}