如何在测试中模拟 NavParams?

How to mock NavParams in tests?

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

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

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

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

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

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

与其模拟 class,最简单的方法是创建 NavParams class 的实例,然后使用它。 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() 每次)。

这是一个有多个参数的例子

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