【问题标题】:How to test Location in angular 2 with karma+jasmine如何使用 karma+jasmine 在角度 2 中测试位置
【发布时间】:2017-02-01 14:27:07
【问题描述】:

Angular 2 v.2.0.0 - TS + 业力 + 茉莉花。

我测试了这个功能——点击返回上一页:

 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 或其他问题?

【问题讨论】:

    标签: angular karma-jasmine


    【解决方案1】:

    在 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]
        }
    ]);
    

    【讨论】:

    • 对.. 位置取决于 LocationStrategy。如果您将 LocationStrategy 添加到您的导入中,然后将其放在传递给 resolveAndCreate 的数组中的 Location 之前,那可能会起作用。另外值得注意的是,我后来发现这不是“正确”的方法,您现在可以使用 TestBed 来做。一分钟内更新答案!
    • @silencedmessage 我在添加 LocationStrategy 时遇到问题,我无法让它工作 TypeError: Cannot read property 'replace' of undefined 我应该为此打开一个问题?我只是将 Location 和 LocationStrategy 添加到提供程序。
    • @titusfx - 我真的不确定我的头顶。我唯一的想法是检查你的polyfills...取消所有它们的注释,看看它是否开始工作(显然如果它开始工作,你可以追踪你需要哪些特定的)。我记得发生了类似的事情,这就是解决方法。不过,这完全是在黑暗中刺伤。祝你好运!
    【解决方案2】:

    在 Angular 中,来自 @angular/common 的 Location 和默认可用的 DOM Location 对象之间存在混淆。尽管如此,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

    【讨论】:

      【解决方案3】:

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

      describe('MyComponent', () => {
          let component: MyComponent;
          let fixture: ComponentFixture<MyComponent>;
      
      
          beforeEach(async(() => {
              TestBed.configureTestingModule({
                  declarations: [MyComponent],
                  providers: [
                      { provide: LOCATION_TOKEN, useValue: window.history }
                  ]
          })
          .compileComponents();
      }));
      
      beforeEach(() => {
          fixture = TestBed.createComponent(MyComponent);
          component = fixture.componentInstance;
          fixture.detectChanges();
      });
      
          describe(('goBack()'), () => {
      
              it('should be clicked', inject([LOCATION_TOKEN], (_loc: Location) => {
                  spyOn(_loc, 'back');
                  component.goBack();
                  expect(_loc.back).toHaveBeenCalledTimes(1);
              }));
      
          });
      });
      

      【讨论】:

      • 仅供参考,我使用 window.history 作为值,因为 window.location 没有方法“back()”。您可以将其替换为 window.location 用于“assign()”等其他方法。
      【解决方案4】:
      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');
         }));
      

      【讨论】:

        猜你喜欢
        • 2020-12-07
        • 1970-01-01
        • 1970-01-01
        • 2017-05-01
        • 2015-03-23
        • 1970-01-01
        • 2020-05-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多