如何在测试中模拟NavParams?

时间:2017-01-02 20:36:49

标签: unit-testing angular ionic2 angular2-testing

这可能只是一个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)时它们都期望不同的结果,模拟变得越来越棘手。

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

4 个答案:

答案 0 :(得分:12)

您可以通过实施自己的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},
    ]
  });
})

答案 1 :(得分:6)

最简单的方法是创建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())。

答案 2 :(得分:4)

我用我自己的这种技术变体修改了@ 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;
  }
}

答案 3 :(得分:0)

以下是多个参数的示例

<强> 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()
  })