#angular #unit-testing #jasmine
#angular #модульное тестирование #jasmine
Вопрос:
Я пишу модульный тест для класса, который расширяет другой класс и вызывает родительский метод во время выполнения. Поскольку я не хочу иметь дело с родительским классом, есть ли какой-нибудь способ имитировать вызов этого метода? Я пробовал несколько способов, но ничего не получалось
class A {
doSomething(){
console.log(123);
}
}
class B extends A {
work(){
this.doSomething();
}
}
Как я могу издеваться над этим вызовом функции и возвращать что-то еще в модульном тестировании для класса B?
Я попробовал следующее :
spyOn(b,'doSomething');
spyOn(Object.getPrototypeOf(b),'doSomething');
Ошибок нет, он просто продолжает вызывать исходный родительский метод
Комментарии:
1. Было бы неплохо показать нам, что именно вы пробовали до сих пор и какие конкретные ошибки где.
2. Обновлено @Erbsenkoenig
Ответ №1:
Что вы могли бы сделать, но я бы не рекомендовал это, так это отключить сам родительский метод внутри вашего класса B.
Я бы не рекомендовал этот подход, потому что вы бы заглушили что-то внутри класса, который вы тестируете. Я бы предпочел заглушки, которые выполняются внутри этого родительского метода.
Но если вы действительно хотите отключить этот метод, вы могли бы сделать что-то в этом роде:
describe('DataService', () => {
let service: DataService;
beforeEach(async(() => {
TestBed.configureTestingModule({ providers: [DataService] });
}));
beforeEach(() => {
service = TestBed.get(DataService); // would be inject in newer angular versions
});
it('test case 2', () => {
spyOn(service as any, 'parentMethod').and.returnValue(5);
expect(service.getData()).toEqual(5);
});
});
где DataService
было бы
@Injectable({
providedIn: 'root'
})
export class DataService extends AbstractDataService {
constructor() {
super();
}
getData() {
return this.parentMethod();
}
}
и AbstractDataService
@Injectable({
providedIn: 'root'
})
export class AbstractDataService {
constructor() { }
parentMethod() {
console.log('parent method');
return null;
}
}
Работает и для компонентов. Но опять же: не рекомендуется издеваться над методами внутри тестируемого объекта !!
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppComponent, AbstractAppComponent],
schemas: [NO_ERRORS_SCHEMA],
bootstrap: [AppComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
});
it('should mock method', () => {
spyOn(component as any, 'abstractMethod').and.returnValue(10);
fixture.detectChanges();
expect(component.myMethod()).toEqual(10);
});
});
Stackblitz с тестовыми примерами как для сервиса, так и для компонента
Комментарии:
1. имеет смысл, но единственное отличие в моем случае — это компонент, а не сервис. И этот подход не работает, когда вы пытаетесь отключить метод из родительского класса компонента. Можете ли вы помочь с этим?
2. это работает так же. вместо того, чтобы шпионить за сервисом, вы будете шпионить за методом внутри вашего компонента.
3. service = TestBed.get(DataService); это не будет работать для компонента. Я пробовал spyOn (component, ‘parentMethod’); но он вызывает только исходный метод
4. Когда вы работаете с тестовым стендом, вы получите экземпляр вашего компонента. И вы можете использовать для этого методы-заглушки, как и в ваших сервисах
5. Взгляните на stackblitz, я включил версию компонента.