如何在订阅Angular7单元测试用例中对代码进行单元测试

Posted

技术标签:

【中文标题】如何在订阅Angular7单元测试用例中对代码进行单元测试【英文标题】:How to unit test code inside subscribe for Angular7 unit test case 【发布时间】:2019-09-14 11:10:24 【问题描述】:

我想对所有代码进行单元测试并获得覆盖率,但我无法获得订阅内存在的代码的覆盖率我能够监视服务和功能,但在订阅内我无法进行单元测试并获得代码覆盖率。以下是 Angular 7 代码。

LoadListData(type) 
    this.itemListEnvName = [];
    if (type === 'EnvirnmentList') 
      this.environmentBookingService.getBookedEnv()
        .subscribe(
          (environmentBookingsData: EbEnvironmentBooking[]) => 
            if (environmentBookingsData.length > 0) 
              this.itemListEnvNameList = environmentBookingsData;
              this.itemListEnvName = [];
              this.itemListEnvNameList.forEach(element => 
                const obj = ;
                obj['id'] = element['environmentId'];
                obj['itemName'] = element['environmentName'];
                this.itemListEnvName.push(obj);
                this.generateCheckDisable = false;
              );
             else 
              this.generateCheckDisable = true;
            
          ,
          (error) => 
            this.showMessage('No Response From Delivery DB API');
          
        );
     else 

      this.showMessage('No Response From Delivery DB API');
    


  

单元测试用例中的代码就像

 it('should call getBookedEnv service ', function () 
    const service = TestBed.get(EnvironmentBookingService); // get your service
    spyOn(service, 'getBookedEnv').and.callThrough(); // create spy
    component.LoadListData('EnvirnmentList');
    expect(service.getBookedEnv).toHaveBeenCalledWith();

  );

如何在订阅中对代码进行单元测试,即

if (environmentBookingsData.length > 0) 
              this.itemListEnvNameList = environmentBookingsData;
              this.itemListEnvName = [];
              this.itemListEnvNameList.forEach(element => 
                const obj = ;
                obj['id'] = element['environmentId'];
                obj['itemName'] = element['environmentName'];
                this.itemListEnvName.push(obj);
                this.generateCheckDisable = false;
              );
             else 
              this.generateCheckDisable = true;
            

【问题讨论】:

好吧,确保服务确实返回了一个非空数组。您通常通过实际模拟服务并使其返回您想要的内容而不是使用服务的实际实现来做到这一点。 以数组形式获取响应。你能给我一些代码示例吗?? spyOn(service, 'getBookedEnv').and.returnValue(of(theArrayForWhichYouWouldLikeToTestYourSuscribeCallback)); 【参考方案1】:

您需要模拟该服务并让它返回一个 Observable。我在StackBlitz 中汇总了一个简单的示例,以展示一种使用您的代码处理此问题的方法。

StackBlitz 中的注意事项:

我用 spyObject 模拟了服务,所以以后不需要监视服务。 在这个 spyObject 中,我将内部函数 getBookedEnv() 的返回值设置为 Observable - 这允许执行订阅中的代码。 对于任何实际测试,您应该将当前由 getBookedEnv() 返回的空对象替换为一些合理模拟的数据。 注意提供者数组以及我用间谍对象替换服务的位置。

这是 StackBlitz 的描述:

describe('BannerComponent', () => 
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  const envBookingServiceSpy = jasmine.createSpyObj('EnvironmentBookingService', 
    getBookedEnv: of(/* mock environmentBookingsData here */)
  );


  beforeEach(async(() => 
    TestBed.configureTestingModule(
      declarations: [ MyComponent ],
      providers: [
         provide: EnvironmentBookingService, useValue: envBookingServiceSpy ,
      ]
    )
    .compileComponents();
  ));

  beforeEach(async(() => 
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
  ));

  it('should call getBookedEnv service ', function () 
    const service = TestBed.get(EnvironmentBookingService); // get your service
    // spyOn(service, 'getBookedEnv').and.callThrough(); // create spy
    component.LoadListData('EnvirnmentList');
    expect(service.getBookedEnv).toHaveBeenCalledWith();
  );
);

我希望这可以帮助您了解如何在您的方法的订阅中开始测试。

【讨论】:

谢谢 dmcgrandle,但是考虑到 this.environmentBookingService.getBookedEnv('data') 中传递了一些参数,上面的答案会如何变化? @Darshantheerth - 不确定我是否完全理解您的问题,因为 OP 的原始示例显然没有将参数传递给该方法。但理论上,如果getBookedEnv() 传递了一个参数,我会假设它仍然会返回一个 Observable,所以我给出的示例不会改变。如果您要求测试传递给服务方法的参数,那可能应该在服务测试中完成,而不是在组件测试中(尽管您可以在这里完成)。如果您仍然感到困惑,我建议您提出一个包含所有详细信息的新问题并以这种方式获得帮助。 :) 感谢您的意见。上面的代码运行良好。【参考方案2】:

如果您想测试subscribe 中的代码,您必须模拟您的服务调用,然后测试您在subscribe 中修改的组件变量,例如this.itemListEnvNamethis.generateCheckDisable

这可能看起来像这样:

 it('should call getBookedEnv service ', function () 
    const service = TestBed.get(EnvironmentBookingService); // get your service
    spyOn(service, 'getBookedEnv').and.callFake(() => 
      return of([]); // or return a list of bookings in case you want to test the first part of the if statement 
    );
    component.LoadListData('EnvironmentList');
    expect(service.getBookedEnv).toHaveBeenCalledWith();

    // additional tests that verify the inside of the subscribe (change below in case the mocked service returned something)
    expect(component.itemListEnvName).equalTo([]);
    expect(component.generateCheckDisable).equalTo(false);
  );

【讨论】:

以上是关于如何在订阅Angular7单元测试用例中对代码进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Python单元测试:在单元测试用例中转换旧测试

Symfony4中的单元测试接口测试

如何在 ios XCTestCase 中对两个对象不相等进行单元测试

无法绑定到“(ngModel”,因为它不是角度单元测试用例中“输入”的已知属性

是否可以在 IOS 的 XCTest 单元测试用例中模拟方法(带参数)调用

如何在 java 中对 jdbc 代码进行单元测试? [关闭]