angular - Angular2'de canActivate koruma metodunu Jasmine kullanarak nasıl birim testi yapabilirim?


Bu tür bir soru sorduğum için özür dilerim. Ama canActivate guard dosyasının testini yazma ile ilgili hiçbir blog veya YouTube eğitimi bulamıyorum. Resmi belgelerde de herhangi bir şeyden bahsedilmemiş.

Her türlü yardım çok takdir edilecektir.

Cevap #1

Kimse soruma cevap vermediği için, bu durumu yaşayabilecek insanlara yardımcı olmak amacıyla referans olarak kod parçacığımı yapıştırıyorum.

sampleLoggedIn.guard.ts

import {Injectable} from '@angular/core';
import {Router, CanActivate} from '@angular/router';
import {StorageService} from '../storage.service';

@Injectable()
export class LoggedInGuard implements CanActivate {
    constructor(private router: Router, private storageService: StorageService) {
    }

    /**Overriding canActivate to guard routes
     *
     * This method returns true if the user is not logged in
     * @returns {boolean}
     */
    canActivate() {
        if (this.storageService.isLoggedIn) {
            return true;
        } else {
            this.router.navigate(['home']);
            return false;
        }
    }
}

sampleLoggedIn.guard.spec.ts

import {TestBed, async} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import {CommonModule} from '@angular/common';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
import {Router} from '@angular/router';
import 'rxjs/add/operator/map';
import {LoggedInGuard} from './loggedin.guard';
import {StorageService} from '../storage.service';
import {CookieService} from 'angular2-cookie/core';

describe('Logged in guard should', () => {
    let loggedInGuard: LoggedInGuard;
    let storageService: StorageService;
    let router = {
        navigate: jasmine.createSpy('navigate')
    };

    // async beforeEach
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [FormsModule, CommonModule, HttpModule],
            providers: [LoggedInGuard, StorageService, CookieService,
                {provide: Router, useValue: router}
            ]
        })
            .compileComponents(); // compile template and css
    }));

    // synchronous beforeEach
    beforeEach(() => {
        loggedInGuard = TestBed.get(LoggedInGuard);
        storageService = TestBed.get(StorageService);
    });

    it('be able to hit route when user is logged in', () => {
        storageService.isLoggedIn = true;
        expect(loggedInGuard.canActivate()).toBe(true);
    });

    it('not be able to hit route when user is not logged in', () => {
        storageService.isLoggedIn = false;
        expect(loggedInGuard.canActivate()).toBe(false);
    });
});

Cevap #2

Bu soru oldukça eski - ama şu anda ben de kendim detaylı bir birim testi dokümantasyonu bulmaya çalışırken, yaklaşımımı burada paylaşmak istedim. Genel olarak, eğer bekçi/servis/bileşen/ne olursa olsun bağımlılıklar varsa, bunların hepsinin taklit edilmesi gerektiğini ve gerçek servislerin kullanılmaması gerektiğini düşünüyorum. Çünkü bu servisler, bekçiyi test etmek istediğimiz birim testinde test etmek istediğimiz şeyler değil - sadece bekçiyi test etmek istiyoruz. İşte bir gözlemleyen (observable) döndüren bir bekçi için nasıl yapacağımın genel bir örneği:

import { MyGuard } from './path/to/your/guard';
import { TestBed } from '@angular/core/testing';
import { finalize } from 'rxjs/operators';

describe('MyGuard Test', () => {
    const createMockRoute = (id: string) => {
    return {
      params: { id: id }
    } as any;
  };

  const createMockRouteState = () => null;
  let guard: MyGuard;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        MyGuard,
      ]
    });

    guard = TestBed.get(MyGuard);
  });

  it('should not be able to activate invalid route', done => {
    const route = createMockRoute(null);
    const state = createMockRouteState();
    const res$ = guard.canActivate(route, state);
    res$.pipe(finalize(done)).subscribe(res => expect(res).toBeFalsy());
  });
});

ve bu, sizin özel durumunuzda yapacağım şeydir (angular 6 ile çalışmalı, canActivate ayrıca 2 parametre almalı):

import { LoggedInGuard } from './loggedin.guard';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { StorageService } from '../storage.service';

describe('LoggedInGuard', () => {
  let guard: LoggedInGuard;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        LoggedInGuard,
        { provide: Router, useClass: { navigate: () => null } },
        { provide: StorageService, useClass: { } }
      ]
    });

    guard = TestBed.get(LoggedInGuard);
  });

  it('should not be able to activate when logged out', () => {
    const storageService = TestBed.get(StorageService);
    storageService.isLoggedIn = false;
    const res = guard.canActivate(null, null);
    expect(res).toBeFalsy();
  });

  it('should be able to activate when logged in', () => {
    const storageService = TestBed.get(StorageService);
    storageService.isLoggedIn = true;
    const res = guard.canActivate(null, null);
    expect(res).toBeTruthy();
  });
});

İlgili makaleler