首页 > 解决方案 > 商店中的角度测试流

问题描述

我有 2 项服务AuthenticationStoreNavigationStore它们具有user$links$流作为links依赖于的属性user$user$可以通过login()logout()方法进行调整AuthenticationStore

服务按预期工作,我对它们进行单元测试并设定期望有问题。我的测试代码如下所示:

describe('NavigationStore', () => {
  const AuthenticationStoreService = { user$: new BehaviorSubject<User>(null) };
  let NavigationStoreService: NavigationStore;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        NavigationStore,
        {
          provide: AuthenticationStore,
          useValue: AuthenticationStoreService
        }
      ]
    })
    .compileComponents();

    NavigationStoreService = TestBed.get(NavigationStore);
  });
  it('should have Logout Admin user', async(() => {
    AuthenticationStoreService.user$.next({
      id: '',
      email: '',
      group: 'A',
    })

    NavigationStoreService.links$.subscribe(
      (links) => {
        expect(links).toEqual([
          {
            title: 'Logout',
            path: '/logout',
            acl: 'A'
          }
        ]);
      }
    );
  }));

  it('should have Login Guest user', async(() => {
    AuthenticationStoreService.user$.next({
      id: '',
      email: '',
      group: '0',
    })

    NavigationStoreService.links$.subscribe(
      (links) => {
        expect(links).toEqual([
          {
            title: 'Login',
            path: '/login',
            acl: '0'
          }
        ]);
      }
    );
  }));
});

我混合了“Spec ...没有期望”。或者第二个测试有管理员用户的结果(比如有前一个测试的值)。

服务代码:

导航商店

const links: Navigation[] = [
  { title: 'Login', path: '/login', acl: '0' },
  { title: 'Logout', path: '/logout', acl: 'A' },
];

@Injectable({
  providedIn: 'root',
})
export class NavigationStore {
  private subject = new BehaviorSubject<Navigation[]>(null);
  links$: Observable<Navigation[]> = this.subject.asObservable();

  constructor(private auth: AuthenticationStore) {
    this.links$ = this.auth.user$.pipe(
      map((user) => links.filter((link) => link.acl.includes(user ? user.group : '0')))
    );
  }
}

身份验证存储

const noUser = {
  id: '',
  email: '',
  group: '0'
};

@Injectable({
  providedIn: 'root',
})
export class AuthenticationStore {
  private subject = new BehaviorSubject<User>(null);
  user$: Observable<User> = this.subject.asObservable();

  constructor(private http: HttpClient) {
    const userProfile = localStorage.getItem(USER_DATA);
    if (userProfile) {
      this.subject.next(JSON.parse(userProfile));
    } else {
      this.subject.next(noUser);
    }
  }

  login(email: string, password: string): Observable<User> {
    return this.http.post<User>(URL + '/users/login', { email, password })
      .pipe(
        tap(user => {
          localStorage.setItem(USER_DATA, JSON.stringify(user));
          this.subject.next(user);
        }),
        catchError(() => {
          this.logout();
          return throwError('');
        }),
        shareReplay()
      );
  }

  logout() {
    localStorage.removeItem(USER_DATA);
    this.subject.next(noUser);
  }
}

我究竟做错了什么?

标签: angularunit-testingrxjsobservable

解决方案


您应该尝试像这样移动第一个AuthenticationStoreService内部的初始化beforeEach-

describe('NavigationStore', () => {
  let AuthenticationStoreService;
  let NavigationStoreService: NavigationStore;

  beforeEach(() => {
    AuthenticationStoreService = { user$: new BehaviorSubject<any>(null) };
    TestBed.configureTestingModule({
      providers: [
        NavigationStore,
        {
          provide: AuthenticationStore,
          useValue: AuthenticationStoreService
        }
      ]
    })
    .compileComponents();

    NavigationStoreService = TestBed.get(NavigationStore);
  });

如上所述修改代码后,我看到您的所有测试都通过了。你也可以试试看它是否有效?


推荐阅读