使用TestBed检测服务存根的更改

时间:2017-03-14 04:06:46

标签: unit-testing angular stub injectable

这是使用angular2文档中提供的Node* temp = root->left; temp = new Node(5, NULL, NULL, NULL); Component使用存根的测试示例。

当我尝试构建并运行它时,我发现该组件没有获取第二个测试用例的更改。我总是看到这个消息。

服务如下:

从@ angular / core';

导入{Injectable}
Service

该组件如下所示:

@Injectable()
export class UserService {
  isLoggedIn: true;
  user: { name: string };
}

这是有问题的单元测试:

import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';

@Component({
  moduleId: module.id,
  selector: 'app-welcome',
  templateUrl: './welcome.component.html'
})
export class WelcomeComponent implements OnInit {
  welcome = '--- not initialized yet';

  constructor (private userService: UserService) {}

  ngOnInit () {
    this.welcome = this.userService.isLoggedIn ?
      'Welcome, ' + this.userService.user.name :
      'Please log in.';
  }
}

错误总是:

import { async, TestBed, ComponentFixture, ComponentFixtureAutoDetect } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { UserService } from './user.service';
import { WelcomeComponent } from './welcome.component';


let fixture: ComponentFixture<WelcomeComponent>;
let comp: WelcomeComponent;
let de: DebugElement;
let el: HTMLElement;
let userService: UserService;

describe('Welcome Component (testing a component with a service)', () => {
  beforeEach(async(() => {
    const userServiceStub = {
      isLoggedIn: true,
      user: {
        name: 'Test User'
      }
    };
    return TestBed.configureTestingModule({
      declarations: [
        WelcomeComponent
      ],
      providers: [
        {
          provide: ComponentFixtureAutoDetect,
          useValue: true
        },
        {
          provide: UserService,
          useValue: userServiceStub
        }
      ]
    }).compileComponents(); // DO NOT USE WITH WEBPACK
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(WelcomeComponent);
    userService = TestBed.get(UserService);
    comp = fixture.componentInstance;
    de = fixture.debugElement.query(By.css('.welcome'));
    el = de.nativeElement;
  });

  it('should welcome the user', () => {
    fixture.detectChanges();
    const content = el.textContent;
    expect(content).toContain('Welcome', '"Welcome..."');
  });

  it('should welcome Bubba', () => {
    userService.user.name = 'Bubba';
    fixture.detectChanges();
    expect(el.textContent).toContain('Bubba');
  });

});

错误:预期&#39;欢迎,测试用户&#39;包含&#39; Bubba&#39;。

调试时,我发现服务存根使用适当的值进行更新。

1 个答案:

答案 0 :(得分:2)

你在这做什么

welcome = '--- not initialized yet';

ngOnInit () {
  this.welcome = this.userService.isLoggedIn ?
    'Welcome, ' + this.userService.user.name :
    'Please log in.';
}

只是一次初始化。对服务的任何后续更新都不会导致重新初始化。

您可以做的是使用订阅系统,您可以订阅更新。也许像是

welcome = '--- not initialized yet';

ngOnInit () {
  this.userService.status$.subscribe(status) => {
     let loggedIn = status.isLoggedIn;
     let user = status.user;
     this.welcome = '...'
  })
}

然后,您需要更改服务以使用Subject或更好的BehaviorSubject,您可以在其中发出新值。这些新的排放将由组件订阅

class UserService {
   private _isLoggedIn: boolean = false;
   private _user = { name: 'Anonymous' };

   private _status = new BehaviorSubject({
     isLoggedIn: this._isLoggedIn
     user: this._user
   });

   get status$() {
     return this._status.asObservable();
   }

   updateUserName(name: string) {
     this._user.name = name;
     this.emit();
   }

   updateIsLoggedIn(loggedIn: boolean) {
     this.isLoggedIn = loggedIn;
     if (!loggedIn) {
       this._user.name = 'Anonymous;
     }
     this.emit();
   }

   private emit() {
     this._status.next({
       isLoggedIn: this._isLoggedIn,
       user: this._user
     })
   }
}

使用Subject,您可以通过调用next(..)来发出新值,并且您传递给它的内容将发送给订阅者。

现在,在测试中,您只需拨打服务updateUserName即可。如果要将服务存根以进行测试,则可以执行类似

的操作
let mockService = {
  status$: new Subject<>();
}

mockService.status$.next(...)

但实际上,使用该服务,不使用任何外部依赖项,实际上没有必要模拟它。

另请注意,因为现在服务是异步的,您应该使用asyncfakeAsync进行测试,例如

import { fakeAsync, async, tick + from '@angular/core/testing';

it('..', fakeAsync(() => {
  service.updateUserName(..)
  tick();
  expect(...)
}))

it('..', async(() => {
  service.updateUserName(..)
  fixture.whenStable().then(() => {
    expect(...)
  })
}))