2017-02-21 106 views
9

我有一个服务(ChildService),它依赖于另一个服务(InteractWithServerService)。稍后的服务(InteractWithServerService)用于进行服务器调用并返回“any”类型的可观察值。为了简单起见,我们假设它返回可观察的。我正在尝试为ChildService编写单元测试。单元测试spyOn angular2中的可观察服务

ChildService

@Injectable() 
export class ApplicationService { 
    constructor(private interactWithServerService:InteractWithServerService){;} 

    public GetMeData():string { 
     var output:string;  
     this.interactWithServerService.get("api/getSomeData"). 
      subscribe(response =>{console.log("server response:", response); 
      output=response});   
     return output; 
    } 
} 

ServerInteractionService

@Injectable() 
export class InteractWithServerService {   
    constructor(private http: Http) { 
     ; 
    }  
    get(url: string): Observable<any> {   
     return this.http.get(this.url); 
    }  
} 

测试用例时,我嘲笑依赖服务工作正常。即,不是优选的

class MockInteractWithServerService { 
    get() { 
     return Observable.of("some text"); 
    }   
} 

describe('Service:ChildService',() => { 
    let childService: ChildService; 

    beforeEach(() => { 
     TestBed.configureTestingModule({ 
      providers: [ 
      { provide: InteractWithServerService, useClass: MockInteractWithServerService }, 
       ChildService], 
     }); 


    beforeEach(inject([ChildService], (actualService: ChildService) => { 
     childService= actualService;   
    })); 

    fit('should call server-call testCall()',() => { 
     let actualReturnvalue= childService.GetMeData();   
     expect(actualReturnvalue).toBe("some text"); 
    }); 
}); 

上述方法如我可能最终写的“n”的依赖关系的“n” mock类。所以我想用spyOn创建我的单元测试。 但是,测试用例不起作用并抛出“错误:没有提供程序的Http!”。虽然我明白错误是什么,但我想知道为什么它会被抛出,尽管我正在监视依赖服务。看起来像“间谍”不工作。

describe('Service:ChildService',() => { 
    let childService: ChildService; 

    beforeEach(() => { 
     TestBed.configureTestingModule({ 
      providers: [ 
      InteractWithServerService, 
       ChildService], 
     }); 

     spyOn(InteractWithServerService.prototype, 'get').and 
      .callFake(()=>  
      {return Observable.of("some text");});  
    }); 
    beforeEach(inject([ChildService], (actualService: ChildService) => { 
     childService= actualService;   
    })); 

    fit('should call server-call testCall()',() => { 
     let actualReturnvalue= childService.GetMeData();   
     expect(actualReturnvalue).toBe("some text"); 
    }); 
}); 

我是否缺少明显的东西?

回答

8

However, the test case doesn't work and throws "Error: No provider for Http!".

因为你仍然在providers服务,所以角试图依然创建

providers: [ 
InteractWithServerService, 
    ChildService], 

你可以做的,而不是建立一个模拟是什么,只是像做

providers: [ 
    { 
    provide: InteractWithServerService, 
    useValue: { get: Observable.of(..) } 
    } 
] 

这是你使用useValue哪些提供任何对象。这将是注入时使用的值。在上面的例子中,它只是你的模拟方法的一些任意对象。

如果你想窥探,这样就可以提供不同的值,你可以注入InteractWithServerService,然后做

spyOn(service, 'get').and.returnValue(Observable.of(...)) 
// do test 

你可以做的另一件事是模拟一个虚拟对象

{ provide: Http, useValue: {} } 
在HTTP

现在InteractWithServerService将工作(只需将类添加到像你目前一样的提供者)。你可以偷窥它

let service = TestBed.get(InteractWithServerService); 
spyOn(service, 'get').and.returnValue(..) 
// do test 
+0

谢谢@peeskillet。奇迹般有效。唯一值得关注的是“useValue”,并为您要调用的每个方法返回一个任意对象。它绝对看起来很脏(而不是很干净)。这是角度想要我们写测试的方式吗? –

+0

“任意对象”与使用模拟类没有任何区别。唯一不同的是,它被封装在一个类中。最后,它们都只是任意的对象。你的班级没有扩展实际的服务界面。是什么让这不是任意的?重要的是该对象具有将被调用的方法。 –

+0

我不认为模拟类比useValue更好。我的观点是 - 模拟类和useValue解决方案与旧方法相比只是注入相关类并监视它们,看起来并不干净。 –