2017-04-19 58 views
0

我试图用茉莉花测试我的角组件。该组件是一个简单的表单,它将一些搜索条件提交给一个服务,该服务然后会关闭并执行Http的东西并返回一组实体。茉莉花spyOn服务时测试角组件

我正在使用Jasmine'spyOn'服务方法,然后返回一个模拟实体。这个模拟实体应该保存在组件中的一个变量中。

我面临的问题是,当我断言实体已成功返回时,我在实体变量中得到了未定义,这使我认为我没有正确设置我的间谍或类似的东西。

任何帮助将不胜感激!

服务:

@Injectable() 
export class DynamicsSearchService { 
    private apiUrl = '/api/DynamicsSearch/Search'; 
    private headers = new Headers({ 'Content-Type': 'application/json' }); 

    constructor(private http: Http) { } 

    search(search: DynamicsSearch): Promise<any[]> { 
     search.fields = this.getDefaultFields(search.entity); 
     return this.http 
      .post(this.apiUrl, JSON.stringify(search), { headers: this.headers }) 
      .toPromise() 
      .then((response) => { return this.extractResults(search.entity, response.json()); }) 
      .catch(this.handleError); 
    } 

    ... 
} 

组件:

@Component({ 
    selector: 'dynamics-search-component', 
    templateUrl: 'dynamics-search.component.html' 
}) 
export class DynamicsSearchComponent { 
    ... 

    entities: any[]; 

    constructor(private searchService: DynamicsSearchService) { } 

    submitSearch() { 
     this.searching = this.searched = true; 
     this.searchService.search(this.model) 
      .then(results => { 
       this.entities = results; 
       this.searching = false; 
       this.searchSuccessful = results !== null && results.length > 0; 
      }); 
    } 

    ... 
} 

测试:

describe('DynamicsSearchComponent',() => { 

    let fixture: ComponentFixture<DynamicsSearchComponent>; 
    let component: DynamicsSearchComponent; 

    let configuration = new Configuration(); 

    beforeEach(() => { 
     TestBed.configureTestingModule({ 
      imports: [ 
       FormsModule, 
       SharedModule 
      ], 
      providers: [ 
       BaseRequestOptions, 
       MockBackend, 
       DynamicsSearchService, 
       Configuration, 
       { 
        provide: Http, 
        useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => { 
         return new Http(backend, defaultOptions); 
        }, 
        deps: [ 
         MockBackend, 
         BaseRequestOptions 
        ] 
       } 
      ], 
      declarations: [ 
       DynamicsSearchComponent 
      ] 
     }).compileComponents(); 
    }); 

    beforeEach(() => { 
     fixture = TestBed.createComponent(DynamicsSearchComponent); 
     component = fixture.componentInstance; 
    }); 

    it('on submit should get a single contact', 
     inject([DynamicsSearchService], (service: DynamicsSearchService) => { 
      var expected = [ 
       { 
        contactid: 'A7806F57-002C-403F-9D3B-89778144D3E1' 
       } 
      ]; 

      const spy = spyOn(service, 'search') 
       .and.returnValue(Promise.resolve(expected));    

      component.model = new DynamicsSearch('contacts', 'A7806F57-002C-403F-9D3B-89778144D3E1', null, 'contactid'); 
      component.submitSearch(); 

      fixture.detectChanges(); 

      expect(spy.calls.count()).toBe(1, `expected service search method to be called once but was called ${spy.calls.count()} times`); 
      expect(component.entities).toBeDefined('no entities returned'); 
      expect(component.entities.length).toBe(1, `expected 1 entity to be returned but only ${component.entities.length} were returned`); 
     } 
    )); 
}); 

它未能在第二期待,因为component.entities是不确定的。

+1

你应该把它分成两个单独的测试 - 这是一个非常糟糕的迹象,你拉'Http来测试组件。用'MockBackend'测试服务,然后用假服务测试组件。此外,您可能需要'fixture.detectChanges()'以确保服务数据返回后所有内容都会更新。 – jonrsharpe

+0

谢谢乔恩。我承担这一点,就是前进,并尝试重构服务位一次/如果我能找出这个问题。提交搜索后,还添加了一个'fixture.detectChanges()',这似乎没有帮助。上面更新。 –

+1

我的观点是,这将帮助你*现在*来隔离问题并创建一个[mcve]。我最近在一些同事的博客上写了一些我们的服务和组件测试,可能有用:http://blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html – jonrsharpe

回答

1

您正在使用异步代码的Promise。将预期置入fixture.whenStable函数中,并将异步函数添加到“它”单元测试中。

fixture.whenStable().then(() => { 
    expect(component.entities).toBeDefined('no entities returned'); 
}); 
+0

谢谢朱莉娅。这似乎解决了这个问题! –