Angular 2(Mock Ionic2) - 没有App

时间:2016-10-11 12:42:27

标签: unit-testing angular mocking ionic2 angular2-testing

我正在尝试为我的应用创建spec.ts。遗憾的是,这是使用ionic-angular中的LoadingController。现在,当我尝试配置模块时,我需要为它提供LoadingController(因为它在模块的构造函数中)。

我目前遇到的问题是LoadingController想要提供App对象/实例。 (_app: App params)

我很绝望所以我自己问了Ionic。 github #8539

但是他们关闭了我的问题,因为这是一个问题,而不是一个问题,尽管我遇到了一些他们没有回应的问题。如果这是不可能的/没有人知道如何,这将是一个耻辱,因为它是一个非常酷的功能,它不仅影响LoadingController,f.e。 AlertController和ToastController也受此影响。

我的testbed配置atm:

TestBed.configureTestingModule({
    declarations: [EventsPage],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    providers: [
      {provide: APICaller, useValue: mockAPICaller},
      {provide: NavController, useValue: mockNavController },
      {provide: LoadingController, useValue: ???????}, //it seems like everything I try to enter here fails.
    ],
    imports: [FormsModule]
  });

和EventsPage构造函数:

constructor(public apiCaller: APICaller, public navCtrl: NavController,
             public loadingCtrl: LoadingController){}

编辑:使用LoadingController

getEvents() {
    // setup a loadingscreen
     let loading = this.loadingCtrl.create({
      content: "Loading..."
    }); 
   // present the loadingscreen
    loading.present();

    // reset the noEvents boolean.
    this.noEvents = true;

    // call the api and get all events
    this.apiCaller.getEvents()
    .subscribe(response => {
      // response is list of events
      this.events = response;
      // if the event is not empty, set noEvents to false.
      if (this.events.length > 0) {
        this.noEvents = false;
      }
      // close the loading message.
     loading.dismiss();
    });
  }

然后将导致此loadingspinner(具有不同的文本)

ionic's Loading

1 个答案:

答案 0 :(得分:7)

使用这种类型的东西,你可能不想在UI中测试任何东西(关于使用LoadingController)。您应该测试的是组件的行为。因此,当您为LoadingController创建模拟时,您想要做的是监视关键方法,并且您的期望应该进行测试以确保您在LoadingController上调用方法。这样做你可以编写像

这样的测试
expect(loadingController.someMethod).toHaveBeenCalled();
// or
expect(loadingController.someMethod).toHaveBeenCalledWith(args);

你的模拟不必遵循被模拟的项目的实际结构。例如,LoadingController.create返回Loading个对象。在你的模拟中,你不需要这个。如果你想要,你可以在调用create时返回模拟本身,而在模拟中只需要Loading所拥有的方法。

请记住,您只是在测试控制器的行为。模拟LoadingController实际上做了什么并不重要,只是你能够调用这些方法,并检查测试以确保它们在时被称为调用。除此之外,你应该假设真正的LoadingController工作。

所以你可以拥有像

这样的东西
let mockLoadingController = {
  // Tried `create: jasmine.createSpy('create').and.returnValue(this)
  // seem this doesn't work. We just create the spy later
  create: (args: any) => { return this; },
  present: jasmine.createSpy('present'),
  dismiss: jasmine.createSpy('dismiss')
};
spyOn(mockLoadingController, 'create').and.returnValue(mockLoadingController);

{ provide: LoadingController, useValue: mockLoadingController }

然后在你的测试中你可以做类似的事情

it('should create loader with args ...', () => {
  ...
  expect(mockLoadingController.create).toHaveBeenCalledWith({...})
})
it('should present the loader', () => {
  ...
  expect(mockLoadingController.present).toHaveBeenCalled();
})
it('should dismiss the loader when the api call returns', async(() => {
  ..
  expect(mockLoadingController.dismiss).toHaveBeenCalled();
}))

这是我现在用来测试的内容

class LoadingController {
  create(args: any) { return this; }
  present() {}
  dismiss() {}
}

@Component({
  template: ''
})
class TestComponent {
  constructor(private loadingController: LoadingController) {}

  setEvents() {
    let loading = this.loadingController.create({hello: 'world'});

    loading.present();
    loading.dismiss();
  }
}

describe('component: TestComponent', () => {
  let mockLoadingController;

  beforeEach(async(() => {
    mockLoadingController = {
      create: (args: any) => { return this; },
      present: jasmine.createSpy('present'),
      dismiss: jasmine.createSpy('dismiss')
    };
    spyOn(mockLoadingController, 'create').and.returnValue(mockLoadingController);

    TestBed.configureTestingModule({
      declarations: [TestComponent],
      providers: [
        { provide: LoadingController, useValue: mockLoadingController }
      ]
    });
  }));

  it('should calling loading controller', () => {
    let comp = TestBed.createComponent(TestComponent).componentInstance;
    comp.setEvents();

    expect(mockLoadingController.create).toHaveBeenCalledWith({ hello: 'world'});
    expect(mockLoadingController.present).toHaveBeenCalled();
    expect(mockLoadingController.dismiss).toHaveBeenCalled();
  });
});

另见: