【问题标题】:How to mock NavParams in tests?如何在测试中模拟 NavParams?
【发布时间】:2017-05-16 22:12:39
【问题描述】:

这可能是 Ionic 2 唯一的问题,因为我在 Angular 2 文档中没有看到 NavParams,但有些概念可能会翻译,所以我标记了两者。

鉴于我调用navparams.get('somekey') 是为了监听传入的参数,因此在测试中模拟 NavParams 是很棘手的。

例如,这是我目前的做法:

export class NavParamsMock {
  public get(key): any {
    return String(key) + 'Output';
  }
}

这适用于真正的基本测试,但如果我有一个组件,我必须测试它gets 一个特定类型的Object,例如User

然后,我可以做类似的事情

export class NavParamsMock {
  public get(key): any {
    if (key === 'user') {
       return new User({'name':'Bob'})
    }
    return String(key) + 'Output';
  }
}

但是,如果您想在另一个测试甚至另一个组件的规范中使用get(user),这不起作用。假设您在 2 个不同的组件中使用 NavParams,并且当您执行 get(user) 时它们都期望不同的结果,模拟变得越来越棘手。

有没有人找到解决这种情况的方法?

【问题讨论】:

    标签: unit-testing angular ionic2 angular2-testing


    【解决方案1】:

    您可以通过实现自己的 setter 方法来获得您选择的价值。

    export class NavParamsMock {
      static returnParam = null;
      public get(key): any {
        if (NavParamsMock.returnParam) {
           return NavParamsMock.returnParam
        }
        return 'default';
      }
      static setParams(value){
        NavParamsMock.returnParam = value;
      }
    }
    

    然后在每个测试中,您都可以访问该服务并设置您自己的 params 对象。

    beforeEach(() => {
      NavParamsMock.setParams(ownParams); //set your own params here
      TestBed.configureTestingModule({
        providers: [
          {provide: NavParams, useClass: NavParamsMock},
        ]
      });
    })
    

    【讨论】:

    • 我收到“'NavParamsMock' 类型的属性 returnParams 不存在......没关系你在 returnParams 之后错过了一个 s。
    • 有一个错字。 returnParam
    【解决方案2】:

    与其模拟类,最简单的方法是创建NavParams 类的实例,然后使用它。 NavParams 使 data 属性可以公开分配,因此可以根据需要在每个测试中进行修改。

    以下示例假设您的页面如下所示:

    @IonicPage()
    @Component({...})
    export class YourPage {
      private data: string;
    
      constructor(navParams: NavParams) {
        this.data = navParams.get('data');
      }
    }
    

    即,您在页面中调用 navParams.get() constructorionViewDidLoad()ngOnInit() 或类似的初始化函数。在这种情况下,要修改NavParams 数据并确保它被正确使用,您需要修改您的测试注入navParams.data 属性,然后重新生成您的页面:

    import {IonicModule, NavParams} from 'ionic-angular';
    import {ComponentFixture, TestBed} from '@angular/core/testing';
    
    describe('YourPage', () => {
      let fixture: ComponentFixture<YourPage>;
      let component: YourPage;
      const data = {data: 'foo'};
      const navParams = new NavParams(data);
    
      function generateFixture() {
        fixture = TestBed.createComponent(YourPage);
        component = fixture.componentInstance;
        fixture.detectChanges();
      }
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          declarations: [YourPage],
          imports: [
            IonicModule.forRoot(YourPage),
          ],
          providers: [
            {provide: NavParams, useValue: navParams},
          ]
        });
        generateFixture();
      });
    
      describe('NavParams', () => {
        it('should use injected data', () => {
          expect(component['data']).toEqual('foo');
        });
        it('should use new injected data', () => {
          const newData = {data: 'bar'};
          navParams.data = newData;
          generateFixture();
          expect(component['data']).toEqual('bar');
        });
      });
    });
    

    如果您的页面到处调用 navParams.get('key') 而不是分配给私有成员,那么在每个测试中只需重新分配 navParams.data 属性就足够了(无需每次都调用 generateFixture())。

    【讨论】:

    • 如果我有 20 个规格需要不同的导航参数,这将不起作用。我想在每个规范中动态设置导航参数以适应每个测试用例。
    • data 上的 NavParams 属性是公共的,如果需要,可以在每个测试中设置。假设您在页面的构造函数中访问NavParams 中的数据成员,您需要重新创建页面以测试是否使用了新数据。但是,如果您总是直接访问NavParams 中的数据而不分配给本地成员,那么只需重新分配NavParams 的数据属性即可。我已经更新了我的答案以匹配。
    【解决方案3】:

    我用我自己的这种技术变体修改了@raj 的答案。 @raj 只允许您设置一个参数。我的允许具有多个参数的键值存储。

    export class NavParamsMock {
      static returnParams: any = {};
    
      public get(key): any {
        if (NavParamsMock.returnParams[key]) {
           return NavParamsMock.returnParams[key];
        }
        return 'No Params of ' + key + ' was supplied. Use NavParamsMock.setParams('+ key + ',value) to set it.';
      }
    
      static setParams(key,value){
        NavParamsMock.returnParams[key] = value;
      }
    }
    

    【讨论】:

    • 属性data 丢失。这是如何完成的:stackoverflow.com/questions/44658048/…
    • @nottinhill 这是一些 ionic 3 变化吗?所以通过我上面的实现,我需要extends NavParams ?
    • 是的,你可以扩展,但我把它全部模拟出来,让我完全控制。
    【解决方案4】:

    这是一个带有多个参数的示例

    NavParamsMock

    export class NavParamsMock {
    
      static returnParams: any = {}
    
      public get (key): any {
        if (NavParamsMock.returnParams[key]) {
          return NavParamsMock.returnParams[key]
        }
      }
    
      static setParams (key, value): any {
        NavParamsMock.returnParams[key] = value
      }
    
    }
    

    将以下内容添加到 TestBed 提供程序

    {provide: NavParams, useClass: NavParamsMock}
    

    单元测试

    it('i am a unit test', () => {
        const navParams = fixture.debugElement.injector.get(NavParams)
    
        navParams.get =
          jasmine
            .createSpy('get')
            .and
            .callFake((param) => {
              const params = {
                'param1': 'value',
                'param2':  'value'
              }
              return params[param]
            })
    
    
        comp.ionViewDidLoad()
      })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-17
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      • 2017-04-19
      • 2020-01-05
      • 1970-01-01
      相关资源
      最近更新 更多