【问题标题】:How to mock ActivatedRouteSnapshot when unit testing a Resolver单元测试解析器时如何模拟ActivatedRouteSnapshot
【发布时间】:2018-01-22 19:34:17
【问题描述】:

我想为我的解析器编写一个单元测试,它需要在其构造函数中采用ActivatedRouteSnapshot,如下所示:

export class MyResolver {
  constructor () {
    // ...
  }

  resolve (private route: ActivatedRouteSnapshot) {
    callFoo(route.params.val);
  }
};

但在我的单元测试中,为激活的路线快照提供模拟数据的最佳方式是什么?当我尝试使用我需要的属性创建一个对象时,我收到一个错误,它不能被强制转换为 ActivatedRouteSnapshot:

it('should call foo', inject([MyResolver], async (myResolver: MyResolver) => {
  const mockRoute = {
    params: {
      val: '1234'
    };
  };

  sinon.spy(callFoo);
  myResolver.resolve(mockRoute); // This is the line that errors
  expect(callFoo.calledWith('1234')).to.be.true;
}));

错误:

Type '{ params: { val: string; }; }' cannot be converted to type 'ActivatedRouteSnapshot'.

如何提供一个模拟的 ActivatedRouteSnapshot 以传递给我的解析器?

【问题讨论】:

    标签: angular unit-testing angular-router


    【解决方案1】:

    您必须像这样提供活动路线:

    import {TestBed} from '@angular/core/testing';
    import {SomeResolver} from './some.resolver';
    import {ActivatedRoute, convertToParamMap} from '@angular/router';
    import {of} from 'rxjs';
    
    describe('SomeResolver', () => {
      let someResolver: SomeResolver;
      let route: ActivatedRoute;
    
      TestBed.configureTestingModule({
        providers: [
          {
            provide: ActivatedRoute,
            useValue: {snapshot: {paramMap: convertToParamMap({id: 'one-id'})}}
          },
          SomeResolver
        ]
      });
    
      beforeEach(() => {
        heroResolver = TestBed.get(HeroResolver);
        route = TestBed.get(ActivatedRoute);
      });
    
      it('should resolve', (() => {
        someResolver.resolve(route.snapshot);
      }));
    });
    

    检查一个更复杂的例子here

    【讨论】:

    • 为什么要通过TestBed获取快照?顺便说一句,TestBed.get() 已被弃用,所以我认为这不是一个好的解决方案,只是用一些模拟变量调用服务。
    • @FlorianLeitgeb 你能举个例子吗?
    • 您在哪里看到 TestBed.get 已弃用?
    • 文档中的弃用警告:angular.io/api/core/testing/TestBed#get。它说以下内容:从 v8.0.0 弃用使用 Type 或 InjectionToken 这不会故意使用已弃用的 jsdoc 标记,因为它会将所有重载呈现为由于 github.com/palantir/tslint/issues/4522 而在 TSLint 中弃用的所有重载。
    【解决方案2】:

    我不确定这是否是最漂亮的解决方案,但您可以像这样模拟路线:

    let route = createSpyObj('Route', ['']);
    route.params = {
      val: '1234'
    }
    

    【讨论】:

    • 我不认为这很丑陋或有点。它就是在这种情况下需要它,我也更喜欢它而不是其他提到的解决方案。
    【解决方案3】:

    如果目的只是将模拟传递给解析器,则没有必要使用 createSpyObj,如其他答案中所建议的那样。此外,最好在解决方案中添加类型安全:

    const mock = <T, P extends keyof T>(obj: Pick<T, P>): T => obj as T;
    
    it('should call foo', () => {
        const route = mock<ActivatedRouteSnapshot, 'params'>({
            params: {
                val: '1234'
            }
        });
    
        const resolver = createTheResolver();
        const resolverParams = resolver.resolve(route);
        ...
    });
    

    【讨论】:

    • 谢谢。它更简单直接。
    【解决方案4】:

    请注意,如果您愿意,您也可以简单地将对象转换为 ActivatedRouteSnapshot:

    const mockRoute = {paramMap: convertToParamMap({'id': '123'})} as 
        ActivatedRouteSnapshot;
    
    resolver.resolve(mockRoute);
    

    【讨论】:

      【解决方案5】:

      出于我的目的,这是最简单的事情(这也允许我写入通常为只读的“父”属性:

      const route = Object.assign({}, ActivatedRouteSnapshot.prototype, {
        params: {
          myParam: 'some_value'
        },
        parent: {
          params: {
            myParentParam: 'some_other_value'
          }
        }
      });
      

      然后你只需像这样用'route'调用你的解析器:

      it('should do something with my activated route params', (done) => {
      const route = Object.assign({}, ActivatedRouteSnapshot.prototype, {
        params: {
          myParam: 'some_value'
        },
        parent: {
          params: {
            myParentParam: 'some_other_value'
          }
        }
      });
      service.resolve(route).subscribe(res => {
        expect( ... )
        done();
      });
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-22
        • 2020-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多