[unit-testing] ActivatedRoute의 매개 변수에 의존하는 구성 요소를 단위 테스트하는 방법은 무엇입니까?

개체를 편집하는 데 사용되는 구성 요소를 단위 테스트하고 있습니다. 개체에는 id서비스에서 호스팅되는 개체 배열에서 특정 개체를 가져 오는 데 사용되는 고유 한 항목 이 있습니다. 특정 항목 id은 특히 ActivatedRoute클래스 를 통해 라우팅을 통해 전달되는 매개 변수를 통해 조달됩니다 .

생성자는 다음과 같습니다.

 constructor(private _router:Router, private _curRoute:ActivatedRoute, private _session:Session) {
}

ngOnInit() {
    this._curRoute.params.subscribe(params => {
        this.userId = params['id'];
        this.userObj = this._session.allUsers.filter(user => user.id.toString() === this.userId.toString())[0];

이 구성 요소에서 기본 단위 테스트를 실행하고 싶습니다. 그러나 id매개 변수를 삽입 할 수있는 방법이 확실하지 않으며 구성 요소 에이 매개 변수가 필요 합니다.

그건 그렇고 : 이미 Session서비스에 대한 모의가 있으므로 걱정할 필요가 없습니다.



답변

이를 수행하는 가장 간단한 방법은 useValue속성을 사용하고 모의하려는 값의 Observable을 제공하는 것입니다.

RxJS <6

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
...
{
  provide: ActivatedRoute,
  useValue: {
    params: Observable.of({id: 123})
  }
}

RxJS> = 6

import { of } from 'rxjs';
...
{
  provide: ActivatedRoute,
  useValue: {
    params: of({id: 123})
  }
}


답변

나는 이것을하는 방법을 알아 냈다!

ActivatedRoute서비스 이므로 모의 서비스를 설정할 수 있습니다. 이것을 모의 서비스라고합시다 MockActivatedRoute. ActivatedRoute에서 MockActivatedRoute다음과 같이 확장 합니다.

class MockActivatedRoute extends ActivatedRoute {
    constructor() {
        super(null, null, null, null, null);
        this.params = Observable.of({id: "5"});
    }

라인 super(null, ....)은 4 개의 필수 매개 변수가있는 수퍼 클래스를 초기화합니다. 그러나이 경우에는 이러한 매개 변수에서 아무것도 필요하지 않으므로 null값으로 초기화합니다 . 모든 우리의 필요의 값입니다 params이다 Observable<>. 따라서를 사용 this.params하여의 값을 재정의 하고 테스트 대상이 의존하는 매개 변수 params가되도록 초기화합니다 Observable<>.

그런 다음 다른 모의 서비스와 마찬가지로 초기화하고 구성 요소의 공급자를 재정의합니다.

행운을 빕니다!


답변

각도 8+에는 구성 요소의 ActivatedRoute 또는 라우터에 액세스하기 위해 사용할 수있는 RouterTestingModule이 있습니다. 또한 RouterTestingModule에 경로를 전달하고 요청 된 경로 방법에 대한 스파이를 만들 수 있습니다.

예를 들어 내 구성 요소에는 다음이 있습니다.

ngOnInit() {
    if (this.route.snapshot.paramMap.get('id')) this.editMode()
    this.titleService.setTitle(`${this.pageTitle} | ${TAB_SUFFIX}`)
}

그리고 내 테스트에서 나는 :

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ ProductLinePageComponent ],
      schemas: [NO_ERRORS_SCHEMA],
      imports: [
        RouterTestingModule.withRoutes([])
      ],
    })
    .compileComponents()
  }))

  beforeEach(() => {
    router = TestBed.get(Router)
    route = TestBed.get(ActivatedRoute)
  })

그리고 나중에 ‘it’섹션에서 :

  it('should update', () => {
    const spyRoute = spyOn(route.snapshot.paramMap, 'get')
    spyRoute.and.returnValue('21')
    fixture = TestBed.createComponent(ProductLinePageComponent)
    component = fixture.componentInstance
    fixture.detectChanges()
    expect(component).toBeTruthy()
    expect(component.pageTitle).toBe('Edit Product Line')
    expect(component.formTitle).toBe('Edit Product Line')
    // here you can test the functionality which is triggered by the snapshot
  })

비슷한 방식으로 jasmine의 spyOnProperty 메서드를 통해 관찰 가능 항목을 반환하거나 rxjs 구슬을 사용하여 paramMap을 직접 테스트 할 수 있다고 생각합니다. 시간을 절약 할 수 있으며 추가 모의 클래스를 유지할 필요가 없습니다. 유용하고 의미가 있기를 바랍니다.


답변

angular 2.0 최신 버전에서 테스트 한 방법은 다음과 같습니다.

import { ActivatedRoute, Data } from '@angular/router';

및 공급자 섹션

{
  provide: ActivatedRoute,
  useValue: {
    data: {
      subscribe: (fn: (value: Data) => void) => fn({
        yourData: 'yolo'
      })
    }
  }
}


답변

ActivatedRoute의 모의를 추가하면됩니다.

providers: [
  { provide: ActivatedRoute, useClass: MockActivatedRoute }
]

class MockActivatedRoute {
  // here you can add your mock objects, like snapshot or parent or whatever
  // example:
  parent = {
    snapshot: {data: {title: 'myTitle ' } },
    routeConfig: { children: { filter: () => {} } }
  };
}


답변

Angular> 5에서 작업하는 일부 사람들의 경우 Observable.of (); 작동하지 않는 경우 ‘rxjs’에서 import {of}를 가져 와서 of () 만 사용할 수 있습니다.


답변

라우팅 경로에 대한 테스트 스위트를 만드는 동안 다음과 같은 문제가 발생했습니다.

{
   path: 'edit/:property/:someId',
   component: YourComponent,
   resolve: {
       yourResolvedValue: YourResolver
   }
}

구성 요소에서 전달 된 속성을 다음과 같이 초기화했습니다.

ngOnInit(): void {
   this.property = this.activatedRoute.snapshot.params.property;
   ...
}

테스트를 실행할 때 모의 ActivatedRoute “useValue”에 속성 값을 전달하지 않으면 “fixture.detectChanges ()”를 사용하여 변경 사항을 감지 할 때 정의되지 않습니다. 이는 ActivatedRoute의 모의 값에 params.property 속성이 포함되어 있지 않기 때문입니다. 그런 다음, 픽스처가 컴포넌트에서 ‘this.property’를 초기화하기 위해 모의 useValue에 해당 매개 변수가 있어야합니다. 다음과 같이 추가 할 수 있습니다.

  let fixture: ComponentFixture<YourComponent>;
  let component: YourComponent;
  let activatedRoute: ActivatedRoute;

  beforeEach(done => {
        TestBed.configureTestingModule({
          declarations: [YourComponent],
          imports: [ YourImportedModules ],
          providers: [
            YourRequiredServices,
            {
              provide: ActivatedRoute,
              useValue: {
                snapshot: {
                  params: {
                    property: 'yourProperty',
                    someId: someId
                  },
                  data: {
                    yourResolvedValue: { data: mockResolvedData() }
                  }
                }
              }
            }
          ]
        })
          .compileComponents()
          .then(() => {
            fixture = TestBed.createComponent(YourComponent);
            component = fixture.debugElement.componentInstance;
            activatedRoute = TestBed.get(ActivatedRoute);
            fixture.detectChanges();
            done();
          });
      });

다음과 같이 테스트를 시작할 수 있습니다.

it('should ensure property param is yourProperty', async () => {
   expect(activatedRoute.snapshot.params.property).toEqual('yourProperty');
   ....
});

이제 다른 속성 값을 테스트하고 싶다면 모의 ActivatedRoute를 다음과 같이 업데이트 할 수 있습니다.

  it('should ensure property param is newProperty', async () => {
    activatedRoute.snapshot.params.property = 'newProperty';
    fixture = TestBed.createComponent(YourComponent);
    component = fixture.debugElement.componentInstance;
    activatedRoute = TestBed.get(ActivatedRoute);
    fixture.detectChanges();

    expect(activatedRoute.snapshot.params.property).toEqual('newProperty');
});

도움이 되었기를 바랍니다!