Başlatma Mantığının Bağımlılıklarını Nasıl Mocklamak
Bu makale başlatma mantığının bağımlılıklarını nasıl mocklayacağınızı açıklamaktadır. Temelde, bir Service
nasıl mocklanır ve/veya bir InjectionToken
nasıl mocklanır gibi, bunlar bir yapıcıda bağımlılıklar olarak enjeksiyon yapılır. Ayrıca, bu makale mock'ları değiştirerek başlatma mantığı için farklı değerler sağlama yöntemini ele almaktadır.
Bir bağımlılığa sahip bir deklarasyonumuz olduğunu hayal edelim. Genellikle, deklarasyon bir bileşen, direktif, boru, hizmet veya hatta bir modüldür ve bağımlılıkları hizmetler, token'lar veya daha karmaşık mantık bileşenler ve direktiflerdir; bunlar aynı anahtar elementte bulunur.
class TargetComponent {
// Başka bir yerde kullanılacak bir özellik: bir şablonda veya başka bir yerde.
public name: string;
// Gerekli bağımlılıklar.
constructor(
@Inject(CONFIG) config: ConfigInterface,
user: CurrentUserService,
) {
// Adı hesaplamak için yapıcıdaki iş mantığı.
if (config.displayName === 'first') {
this.name = user.firstName;
} else {
this.name = user.lastName;
}
}
}
Sanırım burada bir sorun fark ettiniz. Doğru, bağımlılıkları mocklamak ve özelleştirmek için çok fazla boilerplate gerekebilir, çünkü bunlar yapıcıda kullanılır.
- Her kullanım durumu için hafif farklılıklar olan birçok ek, çoğunlukla kopyala-yapıştır
TestBed.configureTestingModule
- Değerleri ayarlamak için ek
beforeEach
bloğu ileTestBed.inject
TestBed.inject
host bağımlılıklarıyla çalışmazTestBed.inject
ilkel değerleri değiştirmeye izin vermez
Bunu keyifli hale getirmek için, ng-mocks
her it
öncesinde MockInstance
yerleştirmenizi sağlar, bu MockRender
](/docs/frontend/ng-mocks/articles/api/MockRender) veya TestBed.createComponent
kullanarak değerleri ayarlamanızı sağlar ve tüm mock bağımlılıklarının özelleştirilmesini destekler: InjectionToken
, Service
veya Component
, Directive
gibi host bağımlılıkları.
// Varsayılan özelleştirmeleri kullanamıyorsanız gereklidir.
// https://ng-mocks.sudo.eu/extra/install#default-customizations
// Her testten sonra MockInstance tarafından yapılan özelleştirmeleri kaldırır.
MockInstance.scope();
beforeEach(() => {
// TargetComponent'in bağımlılıkları için mock'lar.
return TestBed.configureTestingModule({
declarations: [TargetComponent],
providers: [
MockProvider(CONFIG),
MockProvider(CurrentUserService, {
firstName: 'firstName',
lastName: 'lastName',
}),
],
}).compileComponents();
});
it('ilk adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'first',
}),
);
const fixture = TestBed.createComponent(TargetComponent);
fixture.detectChanges();
expect(fixture.componentInstance.name).toEqual('firstName');
});
it('son adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'last',
}),
);
const fixture = TestBed.createComponent(TargetComponent);
fixture.detectChanges();
expect(fixture.componentInstance.name).toEqual('lastName');
});
Lütfen testlerinizden önce MockInstance.scope();
eklediğinizden emin olun.
Bu, testlerden sonra MockInstance
'ın özelleştirmelerini sıfırlar.
Kazanç, MockInstance
yardımıyla, Angular testinde herhangi bir mock deklarasyonunu özelleştirebilirsiniz,
öyle ki, ister InjectionToken
, Service
veya hatta host Component
veya Directive
olsun.
Optimize edilmiş versiyon
Yukarıdaki örnekteki kod miktarını azaltmak istiyorsanız, MockBuilder
ve MockRender
kullanmalısınız.
MockInstance.scope();
beforeEach(() =>
MockBuilder(TargetComponent, ItsModule).mock(
CurrentUserService,
{
firstName: 'firstName',
lastName: 'lastName',
},
),
);
it('ilk adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'first',
}),
);
const fixture = MockRender(TargetComponent);
expect(fixture.point.componentInstance.name).toEqual(
'firstName',
);
});
it('son adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'last',
}),
);
const fixture = MockRender(TargetComponent);
expect(fixture.point.componentInstance.name).toEqual(
'lastName',
);
});
MockRender
, bileşeni fixture.point.componentInstance
altında sağlar.
Canlı örnek
import {
Component,
Inject,
Injectable,
InjectionToken,
NgModule,
} from '@angular/core';
import {
MockBuilder,
MockInstance,
MockProvider,
MockRender,
} from 'ng-mocks';
import { TestBed } from '@angular/core/testing';
interface ConfigInterface {
displayName: 'first' | 'last';
}
const CONFIG = new InjectionToken<ConfigInterface>('CONFIG');
@Injectable()
class CurrentUserService {
firstName?: string;
lastName?: string;
}
@Component({
selector: 'target',
template: '{{ name }}',
})
class TargetComponent {
// Başka bir yerde kullanılacak bir özellik: bir şablonda veya başka bir yerde.
public name?: string;
// Gerekli bağımlılıklar.
constructor(
@Inject(CONFIG) config: ConfigInterface,
user: CurrentUserService,
) {
// Adı hesaplamak için yapıcıdaki iş mantığı.
if (config.displayName === 'first') {
this.name = user.firstName;
} else {
this.name = user.lastName;
}
}
TargetComponentMockInitializationLogic() {}
}
@NgModule({
declarations: [TargetComponent],
providers: [
{
provide: CONFIG,
useValue: {
displayName: 'first',
},
},
CurrentUserService,
],
})
class ItsModule {}
describe('MockInitializationLogic', () => {
describe('TestBed', () => {
// Varsayılan özelleştirmeleri kullanamıyorsanız gereklidir.
// https://ng-mocks.sudo.eu/extra/install#default-customizations
// Her testten sonra MockInstance tarafından yapılan özelleştirmeleri kaldırır.
MockInstance.scope();
beforeEach(() => {
// TargetComponent'in bağımlılıkları için mock'lar.
return TestBed.configureTestingModule({
declarations: [TargetComponent],
providers: [
MockProvider(CONFIG),
MockProvider(CurrentUserService, {
firstName: 'firstName',
lastName: 'lastName',
}),
],
}).compileComponents();
});
it('ilk adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'first',
}),
);
const fixture = TestBed.createComponent(TargetComponent);
fixture.detectChanges();
expect(fixture.componentInstance.name).toEqual('firstName');
});
it('son adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'last',
}),
);
const fixture = TestBed.createComponent(TargetComponent);
fixture.detectChanges();
expect(fixture.componentInstance.name).toEqual('lastName');
});
});
describe('MockBuilder', () => {
MockInstance.scope();
beforeEach(() =>
MockBuilder(TargetComponent, ItsModule).mock(
CurrentUserService,
{
firstName: 'firstName',
lastName: 'lastName',
},
),
);
it('ilk adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'first',
}),
);
const fixture = MockRender(TargetComponent);
expect(fixture.point.componentInstance.name).toEqual(
'firstName',
);
});
it('son adı kapsar', () => {
// Kullanım durumu için özelleştirme.
MockInstance(
CONFIG,
(): ConfigInterface => ({
displayName: 'last',
}),
);
const fixture = MockRender(TargetComponent);
expect(fixture.point.componentInstance.name).toEqual(
'lastName',
);
});
});
});