Error in angular unit test cases: TypeError: this.userService.currentUser.subscribe is not a function

Error in angular unit test cases: TypeError: this.userService.currentUser.subscribe is not a function

我在 运行 angular 单元测试用例时遇到此错误:

测试结果

SidebarComponent
   × should create
    TypeError: this.userService.currentUser.subscribe is not a function

sidebar.component.spec.ts

describe('SidebarComponent', () => {
  let fixture: ComponentFixture<SidebarComponent>;
  let mockUserService;

  beforeEach(() => {
    mockUserService = jasmine.createSpyObj(['currentUser']);

    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      declarations: [SidebarComponent],
      schemas: [NO_ERRORS_SCHEMA],
      providers: [{ provide: UserService, useValue: mockUserService }]
    });

    fixture = TestBed.createComponent(SidebarComponent);
  });

  fit('should create', () => {
    mockUserService.currentUser.and.returnValue(of('Here goes an object'));
    fixture.detectChanges();
    expect(SidebarComponent).toBeTruthy();
  });
});

sidebar.component.ts

ngOnInit() {
    this.userService.currentUser.subscribe(currentUser => {
        // Some code here
    });
}

package.json

"devDependencies": {
    "@types/jasmine": "2.8.8",
    "@types/jasminewd2": "2.0.3",
    "@types/node": "9.6.23",
    "jasmine-core": "2.99.1",
    "jasmine-spec-reporter": "4.2.1",
    "karma": "4.2.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "2.0.0",
    "karma-coverage-istanbul-reporter": "1.4.3",
    "karma-jasmine": "2.0.1",
    "karma-jasmine-html-reporter": "1.4.0",
    "karma-junit-reporter": "1.2.0",
    "karma-spec-reporter": "0.0.32",
    "protractor": "6.0.0",
    "rxjs-tslint": "0.1.7",
}

user.service.ts

@Injectable({ providedIn: 'root'})
export class UserService {
  private currentUserSubject = new BehaviorSubject({});
  public currentUser: Observable<User> = this.currentUserSubject.asObservable().pipe(distinctUntilChanged());

  setUser(user) {
      this.currentUserSubject.next({ ...newUser });
  }
}

据我所知,要解决这个问题,我们需要在以下语句中使用:

mockUserService.currentUser.and.returnValue(of('Here goes an object'));

其中的是从 'rxjs' 导入的。当我记录 of('Here goes an object') 的值时,它表明它是可观察的。

我该如何解决这个问题?

你可以像那样做你的嘲笑:

export const mockUserService= {
    currentUser = {
        subscribe() {
          return of({ 
              // whatever here
          });
        }
    }
};

该代码创建了一个伪造的服务。您可以在这个虚假服务中添加被测试组件使用的所有函数和成员。

如何使用spyOn模拟特定的服务方法:

const userService = TestBed.get(UserService);
const mockedResponse = {}; // Modify as per your need
spyOn(userService, 'currentUser').and.callFake(() => {
  return of(mockedResponse);
});

这对我有用。

在对这个测试做了一些工作之后,我发现我们不能使用 spyOn(userService, 'currentUser')。原因很明显,currentUser 不是一个函数,而是一个变量,我们在其中分配了一个 observable。 SpyOn 将在此基础上创建一个假函数,但我们需要的是一个可观察的。所以我们可以使用userService.setUser方法来适当设置currentUser的值。

sidebar.component.spec.ts

describe('SidebarComponent', () => {
  let component: SidebarComponent;
  let fixture: ComponentFixture<SidebarComponent>;
  let userService: UserService;

  beforeEach(done => {
    TestBed.configureTestingModule({
    imports: [HttpClientTestingModule, RouterTestingModule],
    declarations: [SidebarComponent],
    schemas: [NO_ERRORS_SCHEMA]
  })
  .compileComponents()
  .then(() => {
    fixture = TestBed.createComponent(SidebarComponent);
    component = fixture.componentInstance;

    userService = TestBed.get(UserService);
    userService.setUser(userInfo);

    fixture.detectChanges();
    done();
  });
 });

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