Angular 6组件测试,将变量转换为HTML

时间:2019-05-23 09:01:00

标签: angular typescript karma-jasmine

我是Angular测试的新手,但遇到了问题。 第一个问题是将变量username放入一个组件中,该组件用于将登录的用户名显示在HTML页面中: 这是测试文件:

describe('HeaderComponent', () => {
  let component: HeaderComponent;
  let fixture: ComponentFixture<HeaderComponent>;
  let app;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ HeaderComponent, DialogListConfigurationComponent, DialogConfirmNewConfigurationComponent ],
      providers: [ MessageService, JwtHelperService, AuthService ],  
      imports: [ DialogModule, MenubarModule, FontAwesomeModule, RouterTestingModule, TreeModule, HttpClientTestingModule, JwtModule.forRoot({
        config: {
          tokenGetter: () => {
            return sessionStorage.getItem(environment.tokenName);
          },
          //Exclude this URL from JWT (doesn't add the authentication header)
          blacklistedRoutes: [
            '/api/login',
          ]
        }
      }), ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HeaderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

组件是这样的:

export class HeaderComponent implements OnInit {
  @Output() sidebarEvent = new EventEmitter();
  @Output() clickOkButtonListConfigurationsEvent = new EventEmitter();
  username: String = this.authService.decodeToken.username;
  items = [] as MenuItem[];
  dialogListConfigurationVisible: boolean = false;
  faUserCircle = faUserCircle;
  defaultConfigurations: Configuration[];
  configurationCreated: boolean = false;
  dialogConfirmCreationVisible: boolean = false;
  constructor(private configurationService: ConfigurationService, private authService: AuthService) {   }

  ngOnInit() {
  ...
  }

身份验证服务方法:

get decodeToken(): Jwt {
  return this.jwtHelper.decodeToken(this.getSessionToken);
}

should create测试失败,TypeError: Cannot read property 'username' of null

2 个答案:

答案 0 :(得分:3)

您需要模拟您的AuthService ,因为这是组件测试。

您可以通过在模块初始化代码中提供一个对象来实现

TestBed.configureTestingModule({
  declarations: [ HeaderComponent, DialogListConfigurationComponent, DialogConfirmNewConfigurationComponent ],
  providers: [
    MessageService,
    JwtHelperService,
    {provide: AuthService, useClass: AuthServiceMock} ],  
  imports: [ DialogModule, MenubarModule, FontAwesomeModule, RouterTestingModule, TreeModule, HttpClientTestingModule, JwtModule.forRoot({
    config: {
      tokenGetter: () => {
        return sessionStorage.getItem(environment.tokenName);
      },
      //Exclude this URL from JWT (doesn't add the authentication header)
      blacklistedRoutes: [
        '/api/login',
      ]
    }
  }), ]
})
.compileComponents();

AuthServiceMock类应实现与原始接口相同的接口。可能是这样的:

export class AuthServiceMock {
  // ...
  decodeToken: {
    username: 'testUser'
  };
}

然后,如果您不想在模拟中设置默认值,请在创建组件之前设置模拟类。

注意::您可以在不创建模拟的情况下完成最后一步,但这会破坏测试中关注点的分离。

beforeEach(() => {
    let authServiceMock: AuthServiceMock = TestBed.get(AuthService);
    authServiceMock.decodeToken = { username: 'anotheruser' };

    fixture = TestBed.createComponent(HeaderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

这应该允许HeaderComponent运行this.authService.decodedToken.username行。

作为准则:需要模拟依赖于外部数据的依赖项。

如果以前在测试模块初始化中包括了原始AuthService的依赖项,那么您也可以删除它们。例如,如果JwtHelperService仅在内部用于AuthService,则测试模块可以排除该提供程序。

答案 1 :(得分:0)

在@Thatkookooguy答案中,我遇到了问题,并将这两个原始值添加到beforeEach中,避免使用模拟对象

const authService: AuthService = TestBed.get(AuthService);
authService.saveToken("token string");