2016-09-14 87 views
2

使用TestBed,我們能夠爲依賴注入提供的類創建模擬類。例如,MyButtonClass可以訪問ElementRefMyService,因爲它們是通過依賴注入實現的,所以我們可以覆蓋它們。我遇到的問題是,爲了編寫Jasmine測試,我必須創建模擬類來覆蓋不使用依賴注入進行訪問的類的方法。Angular 2 TestBed,無依賴注入的模擬方法

在這種情況下,ScriptLoader.load將在全局空間中加載ThirdPartyCheckout。這意味着,當Jasmine讀取訂閱運營商內部的內容時它可能不可用。出於這個原因,我想嘲笑前者,然後是後者。或者也許有不同的方式來解決這個問題。

如果有人可以建議一種創建模擬類以覆蓋ScriptLoader.load方法和ThirdPartyCheckout.configure方法的方法,那將會很棒。

的指令進行測試:

@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); 
         } 
        ); 
     }); 
    } 
} 

下面是測試代碼:

@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'); 
    }; 
    ... 
})); 

除此之外,您可能只想考慮使用DI。使用DI的主要原因之一是更好的可測試性。對於ScriptLoader只是使該方法成爲一種非靜態方法,而對於第三方lib而言,只需爲其創建抽象服務層即可。

+0

我簡單地在'beforeEach()'裏面覆蓋'ScriptLoader.load'並工作。謝謝。但是,你用'beforeEach'和'afterEach'所做的每一個'it'每次都會覆蓋ScriptLoader.load並將它返回給一個空變量,對嗎?那是什麼意思?也許,我沒有區分覆蓋靜態方法和爲函數分配新函數的區別? – jayscript

+0

只需重置它,以便您可以在每個測試中使用不同的方法。如果你想讓所有測試都一樣,你可以使用'beforeAll'和'afterAll'。請記住,靜態方法與類保持一致,而不是實例。所以在這個測試中改變它會影響使用它的其他測試(文件)。所以我們希望在完成我們的測試之前將其重置爲原始方法 –

+0

_「我沒有區分覆蓋靜態方法和爲函數分配新函數的區別嗎?」 - 不確定覆蓋是什麼意思。我認爲你指的是同樣的東西 –