【问题标题】:Can you instantiate a service manually before it is injected into a tested component?您可以在将服务注入测试组件之前手动实例化服务吗?
【发布时间】:2019-11-01 23:54:34
【问题描述】:

我正在尝试在 Angular 中测试一个组件 ProfileComponentProfileComponent 通过注入依赖AuthenticationService

profile.component.ts

constructor(public authenticationService: AuthenticationService) { }

我的ProfileComponent 只是一个页面,除非用户登录,否则无法导航到该页面,因为如果authenticationService.isLoggedIn() 返回false,我的路由器会将所有导航重新路由到该页面之外。

我在ProfileComponent 中的代码因此期望authenticationService.isLoggedIn() 返回true,并且从不检查它。相反,它会根据当前登录的用户执行代码,如果没有用户实际登录,则会中断。

我正在尝试测试ProfileComponent,但AuthenticationService 对象在我调用authenticationService.logIn(username, password) 以阻止ProfileComponent 中的代码中断之前被注入ProfileComponent

这是我想做的事情的想法:

profile.component.spec.ts

describe('ProfileComponent', () => {
  let component: ProfileComponent;
  let fixture: ComponentFixture<ProfileComponent>;
  let authenticationService: AuthenticationService;

  beforeEach((done) => {

    // Configure the AuthenticationService's injections
    TestBed.configureTestingModule({
      imports: [
        HttpClientModule
      ]
    });

    // Get the AuthenticationService object
    authenticationService = TestBed.get(AuthenticationService);
    expect(authenticationService).toBeTruthy();

    // Make sure authentication service is logged in
    authenticationService.login(TestVariables.username, TestVariables.password).then(() => {
      // Configure the ProfileComponent's injections, passing the already logged in AuthenticationService
      TestBed.configureTestingModule({
        declarations: [ ProfileComponent ],
        schemas: [CUSTOM_ELEMENTS_SCHEMA],
        imports: [HttpClientModule],
        providers: [
          {
            provide: AuthenticationService,
            useValue: authenticationService
          }
        ]
      }).compileComponents().then(() => {
        fixture = TestBed.createComponent(ProfileComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
        done();
      });
    });
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

当我尝试这个时,我收到以下错误:

'Cannot configure the test module when the test module has already been instantiated. Make sure you are not using `inject` before `TestBed.configureTestingModule`.

有没有一种方法可以在将服务注入正在测试的组件之前对其执行一些操作?

【问题讨论】:

    标签: angular unit-testing angular-test


    【解决方案1】:

    如果你要测试你的组件,你会想要使用一个虚假的服务来与之交互。 而不是配置测试模块两次,你应该做类似的事情

    const fakeAuthenticationService = jasmine.createSpyObj<AuthenticationService>('auth', ['isLoggedIn']);
    
    // set the response to isLoggedIn
    fakeAuthenticationService.isLoggedIn = jasmine.createSpy('isLoggedIn').and.returnValue(true);
    

    然后在您的提供者中,您将拥有

    {
      provide: AuthenticationService,
      useValue: fakeAuthenticationService
    }
    

    现在,当您的测试运行时,您的组件将收到来自isLoggedIntrue 值。一般来说,您应该对每个服务(组件、管道等)使用类似的策略,以便您的测试仅测试组件。如果您使用真正的依赖项,您可能会冒着让他们的代码影响组件测试的风险。这还允许您控制依赖项返回的内容并测试您的组件是否正确处理每个不同的响应。

    【讨论】:

    • 好主意。我忽略了一个事实,即我通过添加对正常工作的其他代码的依赖来破坏我的单元测试。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-20
    相关资源
    最近更新 更多