2016-09-14 3 views
2

TestBed을 사용하여, 우리는 의존성 주입으로 사용 가능한 클래스에 대한 모의 클래스를 생성 할 수 있습니다. 예를 들어, MyButtonClassElementRefMyService에 액세스 할 수 있습니다. 이들이 종속성 삽입으로 구현되어 있으므로이를 대체 할 수 있습니다. 내가 가지고있는 문제는 재스민 테스트를 작성하기 위해서, 의존성 주입으로 액세스되지 않는 클래스의 메소드를 오버라이드 (override)하기 위해 모의 클래스를 만들어야한다는 것이다.Angular 2 TestBed, 의존성 주입없는 모의 메소드

이 경우 ScriptLoader.load은 전체 공간에 ThirdPartyCheckout을로드합니다. 이것은 Jasmine이 subscribe 연산자 안에있는 것을 읽었을 때 사용할 수 없다는 것을 의미합니다. 이런 이유로 저는 처음과 나중을 조롱하고 싶습니다. 아니면이 문제를 해결할 다른 방법이있을 수 있습니다.

ScriptLoader.load 메서드와 ThirdPartyCheckout.configure 메서드를 재정의하기 위해 모의 클래스를 만드는 방법을 제안 할 수 있다면 좋을 것입니다.

이 지침 테스트 할 :

@Component({ 
    selector: 'test-cmp', 
    template: '' 
}) 
class TestComponent {} 

class mockMyService { 
    getKey() { 
     return Promise.resolve('this is a key in real code'); 
    } 
} 

describe('myButton',() => { 
    beforeEach(() => { 
     TestBed.configureTestingModule({ 
      declarations: [TestComponent, MyButtonClass], 
      providers: [ 
       {provide: MyService, useClass: mockMyService} 
      ] 
     }); 
    }); 

    describe('ngAfterViewInit', fakeAsync(() => { 
     const template = '<div><div myButton></div></div>'; 
     TestBed.overrideComponent(TestComponent, {set: {template: template}}); 
     let fixture = TestBed.createComponent(TestComponent); 
     fixture.detectChanges(); 
     tick(); 
    })); 
}); 

답변

2

기능 일류 시민이되고, 당신은 그냥

let originalFn; 

beforeEach(() => { 
    originalFn = ScriptLoader.load; 
}); 

afterEach(() => { 
    ScriptLoader.load = originalFn; 
}); 

it('...', fakeAsync(() => { 
    ScriptLoader.load = (url, el: Element): Observable<string> => { 
    return Observable.of('HelloSquirrel'); 
    }; 
    ... 
})); 
에 새로운 기능을 할당 할 수 있습니다 : 여기
@Directive({ 
    selector: '[myButton]' 
}) 
export class MyButtonClass implements AfterViewInit { 

    private myKey: string; 

    constructor(private _el: ElementRef, private myService: MyService) {} 

    ngAfterViewInit() { 
     this.myService.getKey() 
      .then((myKey: string) => { 
       this.myKey = myKey; 
       ScriptLoader.load('https://thirdpartyurl.js', this._el.nativeElement) 
        .subscribe(
         data => { 
          this.handeler = ThirdPartyCheckout.configure(<any>{ 
           key: this.myKey 
           // etc 
           // and some methods go here 
          }); 
         }, 
         error => { 
          console.log(error); 
         } 
        ); 
     }); 
    } 
} 

테스트 코드

이 외에도 DI 사용을 고려할 수도 있습니다. DI를 사용하는 주된 이유 중 하나는 더 나은 테스트 가능성입니다. ScriptLoader의 경우 메서드를 비 정적 메서드로 만들고 제 3 자 라이브러리의 경우 추상화 서비스 계층으로 만듭니다.

+0

'beforeEach()'안에 단순히'ScriptLoader.load'를 덮어 쓰고 작업했습니다. 감사. 그러나 beforeEach와 afterEach를 사용하여 수행하는 작업은 매번 ScriptLoader.load를 매번 재정의하여 빈 변수로 다시 가져 오는 것입니다. 맞습니까? 그것의 요점은 무엇입니까? 아마도 정적 메서드를 덮어 쓰고 함수에 새 함수를 할당하는 것과 다른 점을 구분하지 않은 것입니까? – jayscript

+0

원한다면 각 테스트마다 다른 방법을 사용할 수 있도록 재설정하십시오. 모든 테스트에서 똑같이 원한다면'beforeAll'과'afterAll'을 사용할 수 있습니다. 정적 메소드는 클래스가 아닌 인스턴스에 있어야한다는 것을 기억하십시오. 따라서이 테스트에서 변경하면 다른 테스트 (파일)에도 영향을줍니다. 그래서 우리는 테스트를 끝내기 전에 원래의 메소드로 원래의 메소드로 리셋하고 싶습니다. –

+0

_ "정적 메소드를 덮어 쓰는 것과 함수에 새로운 함수를 할당하는 것의 차이를 구분하지 않았습니까?"_ - 덮어 쓰는 것의 의미가 확실하지 않습니다. 제 생각에 당신이 말하는 것은 같은 것입니다. –

관련 문제