简体   繁体   English

如何测试 Angular2 的 router.navigate?

[英]How to test Angular2's router.navigate?

I've run into missing <router-outlet> messages in other unit tests, but just to have a nice isolated example, I created an AuthGuard that checks if a user is logged in for certain actions.我在其他单元测试中遇到了丢失<router-outlet>消息,但为了有一个很好的独立示例,我创建了一个 AuthGuard 来检查用户是否已登录以执行某些操作。

This is the code:这是代码:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (!this.authService.isLoggedIn()) {
        this.router.navigate(['/login']);
        return false;
    }
    return true;
}

Now I want to write a unit test for this.现在我想为此编写一个单元测试。

This is how I start my test:这就是我开始测试的方式:

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [
            RouterTestingModule.withRoutes([
                {
                    path: 'login',
                    component: DummyComponent
                }
            ])
        ],
        declarations: [
            DummyComponent
        ],
        providers: [
            AuthGuardService,
            {
                provide: AuthService,
                useClass: MockAuthService
            }
        ]
    });
});

I created a DummyComponent that does nothing.我创建了一个什么都不做的 DummyComponent。 Now my test.现在我的测试。 Pretend that the service returns false and that it triggers this.router.navigate(['/login']) :假设服务返回 false 并触发this.router.navigate(['/login'])

it('should not let users pass when not logged in', (): void => {
    expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
});

This will throw an exception with "Cannot find primary outlet to load".这将引发“找不到要加载的主要出口”的异常。 Obviously I can use toThrow() instead of toBe(false) , but that doesn't seem like a very sensible solution.显然我可以使用toThrow()而不是toBe(false) ,但这似乎不是一个非常明智的解决方案。 Since I'm testing a service here, there is no template where I can put the <router-outlet> tag.由于我在这里测试服务,因此没有可以放置<router-outlet>标记的模板。 I could mock the router and make my own navigate function, but then what's the point of RouterTestingModule?我可以模拟路由器并制作自己的导航功能,但是RouterTestingModule 的意义何在? Perhaps you even want to check that navigation worked.也许您甚至想检查导航是否有效。

I could mock the router and make my own navigate function, but then what's the point of RouterTestingModule?我可以模拟路由器并制作自己的导航功能,但是RouterTestingModule 的意义何在? Perhaps you even want to check that navigation worked.也许您甚至想检查导航是否有效。

There's no real point.没有真正的意义。 If his is just a unit test for the auth guard, then just mock and spy on the mock to check that it's navigate method was called with the login argument如果他只是 auth 守卫的单元测试,那么只需模拟并监视模拟以检查它的navigate方法是否使用login参数调用

let router = {
  navigate: jasmine.createSpy('navigate')
}

{ provide: Router, useValue: router }

expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
expect(router.navigate).toHaveBeenCalledWith(['/login']);

This is how unit tests should normally be written.这就是单元测试通常应该如何编写的。 To try to test any actual real navigation, that would probably fall under the umbrella of end-to-end testing.为了尝试测试任何实际的真实导航,这可能属于端到端测试的范畴。

If you want to test the router without mocking it you can just inject it into your test and then spy directly on the navigate method there.如果你想在不模拟的情况下测试路由器,你可以将它注入到你的测试中,然后直接监视那里的导航方法。 The .and.stub() will make it so the call doesn't do anything. .and.stub()会成功,所以调用不会做任何事情。

describe('something that navigates', () => {
    it('should navigate', inject([Router], (router: Router) => {
      spyOn(router, 'navigate').and.stub();
      expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
      expect(router.navigate).toHaveBeenCalledWith(['/login']);
    }));
  });

this worked for me这对我有用

describe('navigateExample', () => {
    it('navigate Example', () => {
        const routerstub: Router = TestBed.get(Router);
        spyOn(routerstub, 'navigate');
        component.navigateExample();
    });
});
     it(`editTemplate() should navigate to template build module with query params`, inject(
        [Router],
        (router: Router) => {
          let id = 25;
          spyOn(router, "navigate").and.stub();
          router.navigate(["/template-builder"], {
            queryParams: { templateId: id }
          });
          expect(router.navigate).toHaveBeenCalledWith(["/template-builder"], {
            queryParams: { templateId: id }
          });
        }
      ));

I came up with something like that:我想出了类似的东西:

describe('TestComponent', () => {
  let component: TestComponent;
  let router: Router;
  let fixture: ComponentFixture<TestComponent>;
  const routerSpy = jasmine.createSpyObj('Router', ['navigate']); // create a router spy


  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule
      ],
      declarations: [TestComponent],
      providers: [
        { provide: Router, useValue: routerSpy } // use routerSpy against Router
      ],
    }).compileComponents();
  }));

  beforeEach(() => {
    router = TestBed.inject(Router); // get instance of router 
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it(`should navigate to 'home' page`, () => {
    component.navigateToHome(); // call router.navigate
    const spy = router.navigate as jasmine.Spy; // create the navigate spy
    const navArgs = spy.calls.first().args[0]; // get the spy values
    expect(navArgs[0]).toBe('/home');
  });
});

Inspired with angular docs: https://angular.io/guide/testing-components-scenarios#routing-component受角度文档的启发: https ://angular.io/guide/testing-components-scenarios#routing-component

I am new to unit testing angular/javascript apps.我是单元测试 angular/javascript 应用程序的新手。 I needed a way to mock (or spy) for my unit test.我需要一种方法来模拟(或监视)我的单元测试。 The following line is borrowed from Experimenter and helped me TREMENDOUSLY!以下行是从 Experimenter 借来的,对我帮助很大!

const routerSpy = jasmine.createSpyObj('Router', ['navigate']); const routerSpy = jasmine.createSpyObj('Router', ['navigate']); // create a router spy // 创建一个路由器间谍

I would like to say that I had no idea I could do that with Jasmine.我想说我不知道​​我可以用 Jasmine 做到这一点。 Using that line above, allowed me to then create a spy on that object and verify it was called with the correct route value.使用上面的那一行,我可以在该对象上创建一个间谍,并验证它是使用正确的路由值调用的。

This is a great way to do unit testing without the need to have the testbed and all the ceremony around getting the testing module setup.这是一种进行单元测试的好方法,无需测试平台和围绕设置测试模块的所有仪式。 Its also great because it still allows me to have a fake router object with out the need to stub in all of the parameters, methods, etc etc etc.它也很棒,因为它仍然允许我拥有一个假路由器对象,而无需存根所有参数、方法等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM