【问题标题】:Angular test how to mock ActivatedRoute dataAngular 测试如何模拟 ActivatedRoute 数据
【发布时间】:2020-02-14 08:32:38
【问题描述】:

我在模拟 ActivatedRoute 数据属性时遇到了一个真正的大问题。无论我在做什么,最终都会出现错误消息:Error: <spyOnProperty> : Property data does not have access type get。将存根 const 移动到单独的模拟类也不能解决问题。我发现这应该是直截了当的,但我已经为此苦苦挣扎了几天。

组件

@Component({
  selector: 'app-notifications',
  templateUrl: './notifications.component.html',
  styleUrls: ['./notifications.component.css']
})
export class NotificationsComponent implements OnInit {
  notifications: NotificationEntry[];

  constructor(
    private route: ActivatedRoute,
    private modalService: ModalService,
    private messageBoxService: MessageBoxService,
    private notificationsService: NotificationsService
  ) {}

  ngOnInit() {
    this.route.data.subscribe(
      (data: { notifications: NotificationEntry[] }) => {
        this.notifications = data.notifications;
      }
    );
  }
}

组件.spec

describe('NotificationsComponent', () => {
  let component: NotificationsComponent;
  let fixture: ComponentFixture<NotificationsComponent>;

  const registryVersionBasicData = new RegistryVersionBasicData(
    false,
    'versionId',
    new JsonDate('Unspecified', 631894104000000000),
    'user',
    'comment'
  )

  const notifications = new NotificationEntry(
    new JsonDate('Unspecified', 631894104000000000),
    'summary',
    'message',
    NotificationEntityType.StressScenario,
    'instance name',
    'instance key',
    registryVersionBasicData,
    'additional information')

  const notificationsArray = [notifications]

  beforeEach(() => {
    const activatedRouteStub = { data: of({ notifications: notificationsArray }) };
    const modalServiceStub = {};
    const messageBoxServiceStub = {};
    const notificationsServiceStub = {};

    TestBed.configureTestingModule({
      schemas: [NO_ERRORS_SCHEMA],
      declarations: [NotificationsComponent, OrderPipe, RenderDatePipe, VersionInfoPipe],
      providers: [
        { provide: ActivatedRoute, useValue: activatedRouteStub },
        { provide: ModalService, useValue: modalServiceStub },
        { provide: MessageBoxService, useValue: messageBoxServiceStub },
        { provide: NotificationsService, useValue: notificationsServiceStub },
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(NotificationsComponent);
    component = fixture.componentInstance;
  });

  it('can load instance', () => {
    expect(component).toBeTruthy();
  });

  describe('ngOnInit', () => {
    it('should get notifications entry', () => {
      const activatedRouteStub = TestBed.get(ActivatedRoute);
      spyOnProperty(activatedRouteStub, 'data')

      component.ngOnInit();

      expect(component.notifications).toEqual(notificationsArray)
    });
  });
});

【问题讨论】:

    标签: angular mocking angular-router testbed


    【解决方案1】:
    import { ComponentFixture, TestBed } from '@angular/core/testing';
    import { NO_ERRORS_SCHEMA } from '@angular/core';
    import { NotificationsComponent } from './notifications.component';
    import { ActivatedRoute } from '@angular/router';
    import { ModalService, MessageBoxService, NotificationsService, NotificationEntry, JsonDate, NotificationEntityType, RegistryVersionBasicData } from 'src/app/shared';
    import { OrderPipe } from 'ngx-order-pipe';
    import { RenderDatePipe } from 'src/app/shared/pipes/renderdate.pipe';
    import { VersionInfoPipe } from 'src/app/shared/pipes/versioninfo.pipe';
    import { of } from 'rxjs';
    
    fdescribe('NotificationsComponent', () => {
      let component: NotificationsComponent;
      let fixture: ComponentFixture<NotificationsComponent>;
    
      const registryVersionBasicData = new RegistryVersionBasicData(
        false,
        'versionId',
        new JsonDate('Unspecified', 631894104000000000),
        'user',
        'comment'
      );
    
      const notifications = new NotificationEntry(
        new JsonDate('Unspecified', 631894104000000000),
        'summary',
        'message',
        NotificationEntityType.StressScenario,
        'instance name',
        'instance key',
        registryVersionBasicData,
        'additional information');
    
    
      const route = { data: of({ notifications: [notifications] }) };
    
    
      beforeEach(() => {
        const modalServiceStub = {};
        const messageBoxServiceStub = {};
        const notificationsServiceStub = {};
    
        TestBed.configureTestingModule({
          schemas: [NO_ERRORS_SCHEMA],
          declarations: [NotificationsComponent, OrderPipe, RenderDatePipe, VersionInfoPipe],
          providers: [
            { provide: ActivatedRoute, useValue: route },
            { provide: ModalService, useValue: modalServiceStub },
            { provide: MessageBoxService, useValue: messageBoxServiceStub },
            { provide: NotificationsService, useValue: notificationsServiceStub },
          ]
        });
    
        fixture = TestBed.createComponent(NotificationsComponent);
        component = fixture.componentInstance;
      });
    
      it('can load instance', () => {
        expect(component).toBeTruthy();
      });
    
      describe('ngOnInit', () => {
        it('should get notifications entry', () => {
          component.ngOnInit();
          expect(component.notifications).toEqual([notifications]);
        });
      });
    });
    

    最简单的解决方案。使用:

    const route = { data: of({ notifications: [notifications] }) };
    

    .. 然后,在组件提供程序中使用此值:

    { provide: ActivatedRoute, useValue: route }
    

    .. 作为 ActivatedRoute 的原始模拟。然后,您的测试用例可以如下所示(不需要 TestBed):

      describe('ngOnInit', () => {
        it('should get notifications entry', () => {
          component.ngOnInit();
          expect(component.notifications).toEqual([notifications]);
        });
      });
    

    【讨论】:

      【解决方案2】:

      如下定义你的activatedRouteStub-

      class ActivatedRouteStub {
          private _data = new BehaviorSubject(notifications);
          get data() {
              return this._data;
          }
          set data(notifications: NotificationEntry[]) {
              this.data.next(notifications)
          }
      }
      

      然后在您的提供程序中使用它作为

      { provide: ActivatedRoute, useValue: new ActivatedRouteStub()}
      

      现在您可以通过以下方式更改数据

      const activeRoute = testBed.get(ActivatedRoute);
      activeRoute.data = [new Notification()];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-28
        • 1970-01-01
        • 2018-10-21
        • 2018-10-07
        • 2021-06-17
        • 2018-11-24
        • 2019-01-27
        • 1970-01-01
        相关资源
        最近更新 更多