具有多个嵌套依赖项的Angular 2测试服务

具有多个嵌套依赖项的Angular 2测试服务,angular,unit-testing,Angular,Unit Testing,我的一般问题是,当尝试测试具有其他服务作为依赖项的服务时,如何设置角度测试,其中一些服务具有其他依赖项。此外,我的服务使用可观察和承诺。我需要模拟每个构造函数和方法吗?这就是我得到的错误(在下面的评论中详细说明)似乎表明的。我如何才能最好地完成这一点?我也非常感谢关于如何使用弹珠或指向任何有用资源的指针设置此类测试的指针 我的代码很大程度上受到了这个示例的启发,它似乎实现了我想要做的事情: //我想测试的服务 导出类服务测试{ 建造商( 私人依赖1:依赖1服务, 私人依赖2:依赖2服务 ) {}

我的一般问题是,当尝试测试具有其他服务作为依赖项的服务时,如何设置角度测试,其中一些服务具有其他依赖项。此外,我的服务使用可观察和承诺。我需要模拟每个构造函数和方法吗?这就是我得到的错误(在下面的评论中详细说明)似乎表明的。我如何才能最好地完成这一点?我也非常感谢关于如何使用弹珠或指向任何有用资源的指针设置此类测试的指针

我的代码很大程度上受到了这个示例的启发,它似乎实现了我想要做的事情:

//我想测试的服务
导出类服务测试{
建造商(
私人依赖1:依赖1服务,
私人依赖2:依赖2服务
) {}
.
.
.
.
getData1():Promise{return dependency1.getData1();}//我要测试的方法
getData2(){}
getData2(){}
}
导出类依赖关系1服务{
建造商(
私有依赖1:子依赖1服务,
私有依赖2:子依赖2服务,
私有依赖3:子依赖3服务,
) {}
.
.
.
.
getData1():可观察的{return…}
getData2(){}
getData2(){}
}
导出类Dependency2Service{
建造商(
私有依赖1:子依赖3服务,
私人依赖2:子依赖4服务,
私人依赖3:子依赖5服务,
) {}
.
.
.
.
getData1(){}
getData2(){}
getData2(){}
}
导出类子依赖项1服务{
建造商(
私人依赖1:另一个依赖1服务,
私人依赖2:另一个依赖2服务,
私人依赖3:另一个依赖3服务,
) {}
.
.
.
.
getData1(){}
getData2(){}
getData2(){}
}
//=======================================================================
//测试设置
//=======================================================================
const payload:Observable=of({something1,something2})
导出类MockDependency1Service{
getData1(){return payload};
}
常量数据2=新Promis((解析、拒绝)=>{
设置超时(()=>{
决心([]);
}, 1000);
});
导出类MockDependency2Service{
getData(){return data};
}
描述('要测试的服务',()=>{
让mockDependency1Service=newDependency1Service()
让mockDependency2Service=newDependency2Service();
    
在每个(()=>{
spyOn(MockDependency1Service,'getData1')
spyOn(MockDependency2Service,'getData1')。和.returnValue(有效载荷);});
    
beforeach(()=>TestBed.configureTestingModule({
提供者:[
{provide:Dependency1Service,useValue:mockDependency1Service}
{提供:Dependency2Service,useValue:mockDependency2Service}
}));
//可见
它('应该返回结果',(完成)=>{
const service=new TwilioConnectionService(mockDataService,mockLocalTrack);//在mockDataService上出现错误--“MockDependency1Service”类型的参数不能分配给“Dependency1Service”类型的参数。类型“MockDependency1Service”缺少类型“Dependency1Service”中的以下属性:dependency1、dependency2、dependency3、getData2、getData3--基本上是任何注入的属性或任何me导出类MockDependency1Service中未定义的方法。
const obs=service.getAccessToken()
obs.subscribe(res=>{
setTimeout(()=>{
expect(res.data.jwt).toBe('0234ljksdlkgoier')//data.jwt)
完成()
}, 100);        
});
});

如果您只想对服务进行单元测试,基本方法是只存根/模拟直接依赖项和被测服务使用的方法。您不关心可传递依赖项

使用jasmine,您可以使用
createSpy()
简化设置。angular文档中有很多关于一般测试和包含依赖项的信息

另一个解决方案是让Mock从它所模拟的服务扩展而来,但只有当它只有几个方法时才可用

最简单的解决方案是将其强制转换为
任意

   const service = new TwilioConnectionService(mockDataService as any, mockLocalTrack);
示例:

我们有
BarService
FooService

export class FooService {
  constructor() { }

  getValue (): Observable<string> {
    return from(['foo', 'fooo', 'foooo']);
  }

  other () {
    // ....
  }

export class BarService {
  constructor(private fooService: FooService) { }

  callFoo (): Observable<string> {
    return this.fooService.getValue()
      .pipe(
        map(f => f + 'bar!')
      )
  }
}
使用茉莉花间谍:

  describe('jasmine stub', () => {
    const fooSpy = jasmine.createSpyObj('FooService', ['getValue']);

    it('adds bar to foo service result', () => {
      fooSpy.getValue.and.returnValue(from(['foo']));

      let bs = new BarService(fooSpy);

      bs.callFoo()
        .subscribe(r => {
          expect(r).toEqual('foobar!')
        })
    });
  })
使用茉莉花和茉莉花大理石(必须将其添加到package.json):


这正好捕获了我正在尝试做的事情,实际上我已经尝试了该链接中详细介绍的几个选项,但没有成功。无论出于何种原因,当我执行const
valueServiceSpy=jasmine.createSpyObj('ValueService',['getValue'])
,我无法使用语法
valueServiceSpy.getValue.and.returnValue(stubValue)
和.returnValue(stubValue)
链接到我创建的
valueServicesSpy
。这可能是因为我的
getValue
方法返回一个可观察的对象吗?如果是,我该如何处理?另外,如果我需要为几个方法执行此操作呢?例如
jasmine.createSpyObj('ValueService'),['getValue'、'getValue2'、'getValue3'])
。我如何处理返回每个值的问题?顺便说一句,我的意思是我的
getValue
返回一个可观察的值。我添加了三个带有
observable
的简单测试示例。谢谢!让它同时使用手动和存根选项。对于存根选项,我的问题是,我已经将变量强类型化为实际服务t我试图模仿的是什么,所以在本例中
constfoospy:FooService;f
  describe('manual stub', () => {
    let fooStub = {
      getValue() {
        return from(['foo'])
      }
    }

    it('adds bar to foo service result', () => {
      // without the cast: not assignable error because of other()
      let bs = new BarService(fooStub as any);

      bs.callFoo()
        .subscribe(r => {
          expect(r).toEqual('foobar!')
        })
    });
  })
  describe('jasmine stub', () => {
    const fooSpy = jasmine.createSpyObj('FooService', ['getValue']);

    it('adds bar to foo service result', () => {
      fooSpy.getValue.and.returnValue(from(['foo']));

      let bs = new BarService(fooSpy);

      bs.callFoo()
        .subscribe(r => {
          expect(r).toEqual('foobar!')
        })
    });
  })
  import {cold} from 'jasmine-marbles'; 

  describe('marble', () => {
    const fooSpy = jasmine.createSpyObj('FooService', ['getValue']);

    it('adds bar to foo service result', () => {
      const source = cold('ab|', {a: 'foo', b: 'fooo'});
      const expected = cold('xy|', {x: 'foobar!', y: 'fooobar!'});

      fooSpy.getValue.and.returnValue(source);

      let bs = new BarService(fooSpy);
      expect(bs.callFoo()).toBeObservable(expected);
    });
  })