1
votes

Comment se moquer d'une variable en utilisant l'espion jasmin?

J'essaye de tester un composant de connexion. Je peux me moquer de tout sauf des variables de chaîne. Comment faire?

import {LoginComponent} from './login.component';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '@angular/core';
import {AuthService} from './auth.service';
import {HttpClient, HttpHandler} from '@angular/common/http';
import {JwtHelperService, JwtModule, JwtModuleOptions} from '@auth0/angular-jwt';
import {TokenService} from './token.service';
import {Router} from '@angular/router';
import {Observable, of} from 'rxjs';


describe('LoginComponent', () => {
    let component: LoginComponent;
    let fixture: ComponentFixture<LoginComponent>;

    const JWT_Module_Options: JwtModuleOptions = {
        config: {
            tokenGetter: function () {
                return '';
            },
            whitelistedDomains: []
        }
    };

    const authServiceSpy = jasmine.createSpyObj('AuthService', ['login', 'isLoggedIn']);

    authServiceSpy.login.and.callFake(function () {
        return of({});
    });

    beforeEach(async(() => {

        TestBed.configureTestingModule({
            imports: [
                JwtModule.forRoot(JWT_Module_Options)
            ],
            declarations: [LoginComponent],
            providers: [HttpClient, HttpHandler, JwtHelperService, TokenService,
                [
                    {
                        provide: AuthService,
                        useValue: authServiceSpy
                    },

                    {
                        provide: Router,
                        useClass: class {
                            navigate = jasmine.createSpy('navigate');
                        }
                    }]],
            schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
        }).compileComponents();
    }));

    beforeEach(() => {


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

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

    it('should log in properly without redirect URL', () => {


        authServiceSpy.isLoggedIn.and.callFake(function () {
            return true;
        });
        component.login();

        expect(component.router.navigate).toHaveBeenCalledWith(['/']);
        expect(component.loginSpinner).toEqual(false);

    });

    it('should log in properly with redirect URL', () => {


        authServiceSpy.isLoggedIn.and.callFake(function () {
            return true;
        });


        // this doesn't work
        authServiceSpy.redirectUrl = '/foo';

        component.login();


        expect(component.router.navigate).toHaveBeenCalledWith(['/foo']);
        expect(component.loginSpinner).toEqual(false);

    });

   }
);

Le composant de connexion a un service appelé authService. Je suis capable de tout simuler sauf la chaîne dans authService appelée URL de redirection. Comment faire cela?

@Component({
   selector: 'app-login',
   templateUrl: './login.component.html',
   styleUrls: ['./login.component.scss'])

   export class LoginComponent {
   username: string;
   password: string;
   loginSpinner: boolean;

   constructor(public authService: AuthService, public router: Router) {
   }

   login() {
     this.loginSpinner = true;
     this.authService.login(this.username, this.password).subscribe(() => {
     this.loginSpinner = false;
     if (this.authService.isLoggedIn) {
     // Get the redirect URL from our auth service
     // If no redirect has been set, use the default
     const redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/';

     // Redirect the user
     this.router.navigate([redirect]);
    }
  }, () => {
  // also want to hide the spinner on an error response from server when attempting login
     this.loginSpinner = false;
  });
 }

   logout() {
     this.authService.logout();
    }
}


1 commentaires

J'écrirai une implémentation et enquêterai, mais à l'origine je pensais soit utiliser Jasmines spyOnProperty (obj, propertyName, accessTypeopt) → {Spy} soit faire une simulation.


3 Réponses :


2
votes

Essayez ceci:

const spy = spyOnProperty(authServiceSpy, 'redirectUrl').and.returnValue(
  '/foo'
);
expect(authServiceSpy.redirectUrl).toBe('/foo');
expect(spy).toHaveBeenCalled();


5 commentaires

Le défi est que ce n'est pas une propriété, juste une chaîne. Il n'y a ni getter ni setter, juste une chaîne publique.


Je ne sais pas si cela est possible. Avez-vous vraiment besoin de tester la valeur de la chaîne? Si c'est le cas, je suggère d'ajouter un setter uniquement dans le but de tester


ouais..Je dois admettre que je suis perplexe ... J'ai changé authService pour ressembler à // stocker l'URL afin que nous puissions rediriger après la connexion _redirectUrl: string; set redirectUrl (data: string) {this._redirectUrl = data; } get redirectUrl (): string {return this._redirectUrl; } Et ajouté votre suggestion ... et j'ai toujours une erreur de ne pas obtenir la méthode disponible ... Je suis perplexe ... mais acceptez votre réponse comme correcte car cela semble être l'approche raisonnable


MISE À JOUR: Bien que ce soit une approche raisonnable ... la solution ci-dessous a entièrement résolu mon défi.


MISE À JOUR POUR MISE À JOUR: Errrrm .... depuis que je l'ai accepté ... la solution est maintenant située en haut. : P Celui ci-dessous semble également utile.



5
votes

Pouvez-vous essayer ceci?

Créez une classe simulée:

describe('LoginComponent', () => {
    ...
    let mockAuthService = new MockAuthService();
    ...

    beforeEach(async(() => {
       TestBed.configureTestingModule({
          imports: [...],
          declarations: [...],
          providers: [...,
            [
              {
                   provide: AuthService,
                   useValue: mockAuthService
              },
            ]],
        schemas: [...]
    }).compileComponents();
    ....
    it('should log in properly with redirect URL', () => {
        mockAuthService.redirectUrl = '/foo';
        component.login();
        expect(component.router.navigate).toHaveBeenCalledWith(['/foo']);
        expect(component.loginSpinner).toEqual(false);
    });
    ...

Dans votre test:

class MockAuthService{
     public redirectUrl = "/foo";

     isLoggedIn(){
         /*This can also be defined only for spies*/
         return true;
     }
}

p >


0 commentaires

3
votes

Je suis un peu en retard à la fête, mais il existe un moyen beaucoup plus simple de le faire avec ce que vous avez déjà. Pas besoin de créer une autre classe. Définissez d'abord une variable comme celle-ci:

// this doesn't work
authServiceSpy.redirectUrl = '/foo';
// this DOES work
authService.redirectUrl = '/foo';

Ensuite, une fois que le banc de test a été configuré, définissez-le sur le service réel utilisé par le TestBed dans le dernier code beforeEach () >:

authService = TestBed.get(AuthService);

et enfin, utilisez-le dans votre test pour définir ce que vous voulez sur .redirectUrl:

let authService: AuthService;


2 commentaires

C'est vrai ... c'est vrai! J'aimerais pouvoir accepter des réponses dérangeantes. :)


En tant que PO, c'est entièrement à vous, vous pouvez accepter la réponse que vous souhaitez. Si vous recherchez une suggestion, je vous suggère d'accepter la solution que vous utilisez réellement. :) Bons conseils ici