简体   繁体   English

您可以在将服务注入测试组件之前手动实例化服务吗?

[英]Can you instantiate a service manually before it is injected into a tested component?

I am trying to test a component, ProfileComponent in Angular.我正在尝试测试 Angular 中的组件ProfileComponent ProfileComponent depends on AuthenticationService through injection: ProfileComponent通过注入依赖AuthenticationService

profile.component.ts profile.component.ts

constructor(public authenticationService: AuthenticationService) { }

My ProfileComponent is simply a page, and cannot be navigated to unless the user is logged in because my router re-routes all navigations away from this page if authenticationService.isLoggedIn() returns false .我的ProfileComponent只是一个页面,除非用户登录,否则无法导航到该页面,因为如果authenticationService.isLoggedIn()返回false ,我的路由器会将所有导航重新路由到该页面之外。

My code in ProfileComponent therefor expects authenticationService.isLoggedIn() to return true, and does not ever check it.我在ProfileComponent中的代码因此期望authenticationService.isLoggedIn()返回 true,并且从不检查它。 Instead, it executes code based on the currently logged in user, which would break if no user was actually logged in.相反,它根据当前登录的用户执行代码,如果没有用户实际登录,这将中断。

I am trying to test ProfileComponent , but the AuthenticationService object is injected into ProfileComponent before I can call authenticationService.logIn(username, password) to stop the code in ProfileComponent from breaking.我正在尝试测试ProfileComponent ,但是AuthenticationService object 在我可以调用authenticationService.logIn(username, password)以阻止ProfileComponent中的代码中断之前被注入到ProfileComponent中。

Here's the idea of what I'd like to do:这是我想做的事情的想法:

profile.component.spec.ts 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();
  });
});

When I try this, I am getting the following error:当我尝试这个时,我收到以下错误:

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

Is there a way that I can perform some operations on my service before injecting it into a component that is being tested?有没有一种方法可以在将服务注入正在测试的组件之前对服务执行一些操作?

If you're going to be testing your component you will want to use a fake service for it to interact with.如果你要测试你的组件,你会想要使用一个虚假的服务来与之交互。 Instead of configuring the test module twice, you should do something similar to而不是配置测试模块两次,你应该做类似的事情

const fakeAuthenticationService = jasmine.createSpyObj<AuthenticationService>('auth', ['isLoggedIn']);

// set the response to isLoggedIn
fakeAuthenticationService.isLoggedIn = jasmine.createSpy('isLoggedIn').and.returnValue(true);

Then in your providers you will have然后在您的提供者中,您将拥有

{
  provide: AuthenticationService,
  useValue: fakeAuthenticationService
}

Now when your test runs your component will receive a true value from isLoggedIn .现在,当您的测试运行时,您的组件将从isLoggedIn收到一个true值。 In general you should use a similar strategy for every service (component, pipe, etc) so that your test is ONLY testing the component.通常,您应该对每个服务(组件、pipe 等)使用类似的策略,以便您的测试仅测试组件。 If you use real dependencies you risk having their code affect the test for your component.如果您使用真正的依赖项,您可能会让他们的代码影响您的组件的测试。 This also allows you to control what your dependencies return and test that your component handles each different response correctly.这还允许您控制依赖项返回的内容并测试您的组件是否正确处理每个不同的响应。

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

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