如何用karma + jasmine测试角度2中的位置

时间:2017-02-01 14:27:08

标签: angular karma-jasmine

Angular 2 v.2.0.0 - TS + karma + jasmine。

我测试了这个功能 - 回到点击以前的页面:

 public isClick: boolean = false;

 public backClicked(location: Location): void {
        if (!this.isClick) {
            this.isClick = true;
            this.location.back();
        }
    }

这是我的考验:

describe("NavBarComponent", () => {
    describe("function backClicked(): void", () => {
        let testNavBarComponent: NavBarComponent;
        let loc: Location;
        beforeEach(() => {
            testNavBarComponent = new NavBarComponent(null);
        });
        loc = jasmine.createSpyObj("Location", ["back"]);
        it ("It is backClicked() function test", () => {
            testNavBarComponent.backClicked(loc);
            expect(loc.back).toHaveBeenCalledTimes(1);
        });
    });
});

运行测试后,我遇到了这个错误:TypeError: Cannot read property 'back' of null。可能是createSpyObj或其他问题的问题?

4 个答案:

答案 0 :(得分:3)

在backClicked函数中,您将调用位置this.location的类实例,而不是传递给函数location的位置实例。我假设您的NavBarComponent由于错误消息而注入了Location(默认情况下,事物是未定义的而不是null)。

您可以执行以下操作:

beforeEach(() => {
    // Mock the location here instead, then pass to the NavBarComponent
    loc = jasmine.createSpyObj("Location", ["back"]);
    testNavBarComponent = new NavBarComponent(loc);
});

或者,我使用Angular的ReflectiveInjector课有好运。可用于模拟Angular 2中测试的依赖关系的文档和文章全都是RC的迭代次数,所以我不能100%确定这被认为是最佳实践 :

import { ReflectiveInjector } from '@angular/core';
import { Location } from '@angular/common';

describe("NavBarComponent", () => {
    describe("function backClicked(): void", () => {
        let testNavBarComponent: NavBarComponent;
        let loc: Location;

        beforeEach(() => {
            let injector = ReflectiveInjector.resolveAndCreate([
                LocationStrategy,
                Location
            ]);

            // Get the created object from the injector
            loc = injector.get(Location);

            // Create the spy.  Optionally: .and.callFake(implementation)
            spyOn(loc, 'back');

            // Create NavBarComponent with the spied Location
            testNavBarComponent = new NavBarComponent(loc);
        });

        it ("It is backClicked() function test", () => {
            testNavBarComponent.backClicked(loc);
            expect(loc.back).toHaveBeenCalledTimes(1);
        });
    });
});

修改:现在可以使用TestBed.configureTestingModule完成 https://blog.thoughtram.io/angular/2016/11/28/testing-services-with-http-in-angular-2.html

使用ReflectiveInjector,您也可以像在app.module中一样声明依赖项。例如,模拟Http服务:

let injector = ReflectiveInjector.resolveAndCreate([
    MockBackend
    BaseRequestOptions,
    {
        provide: Http,
        useFactory: (backend, options) => {
            return new Http(backend, options);
        },
        deps: [MockBackend, BaseRequestOptions]
    }
]);

答案 1 :(得分:1)

Angular在@angular/common的位置与默认情况下可用的DOM位置对象之间存在混淆。尽管如此,Angular的版本提供了.go()功能,实际上它只与路由器交互,并且不像DOM对象那样重新加载页面。因此,对于真正的浏览器交互,您必须使用DOM版本,这会给您带来如何测试的问题?

不幸的是,由于它的可写对象,它无法进行间谍活动。 但您可以将其作为值注入组件中。这就是它的样子

export const LOCATION_TOKEN = new InjectionToken<Location>('Window location object');

@Component({
  providers: [
    { provide: LOCATION_TOKEN, useValue: window.location }
  ]
})
export class SomeComponent {
  constructor(@Inject(LOCATION_TOKEN) private location: Location) {}

  useIt() {
    this.location.assign('xxx');
  }
}

有关详细信息,请参阅https://angular.io/guide/dependency-injection#non-class-dependencies

答案 2 :(得分:0)

要在Angular中进行测试(如s-f的回答),您可以将LOCATION_TOKEN注入到TestBed中,如下所示:

base_url = test/url

api_url = ${base_url}/api/url

答案 3 :(得分:0)

beforeEach(async(() => {
       TestBed.configureTestingModule({
         declarations: [ HeroDetailsComponent ],
        providers: [ MyHeroService ],
         imports: [ RouterTestingModule ],
       providers: [{ provide: Location, useClass: SpyLocation }]
       })
         .compileComponents();
     }));

  it('should logout from application', async(() => {
         const location: Location = TestBed.get(Location);

         expect(location.href).toContain('blablabla url');
   }));