如何使用茉莉花间谍模拟变量?

时间:2019-01-22 15:45:46

标签: angular typescript jasmine

我正在尝试测试登录组件。我可以模拟除字符串变量之外的所有内容。该怎么做?

@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();
    }
}

登录组件具有一个名为authService的服务。我可以模拟除authService中称为重定向URL的字符串以外的所有内容。该怎么做?

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);

    });

   }
);

3 个答案:

答案 0 :(得分:2)

尝试一下:

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

答案 1 :(得分:2)

你可以试试吗?

创建一个模拟类:

class MockAuthService{
     public redirectUrl = "/foo";

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

在测试中:

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);
    });
    ...

答案 2 :(得分:1)

我参加聚会有点晚,但是有一种简单的方法可以解决您已有的事情。无需开设其他课程。首先定义一个像这样的变量:

let authService: AuthService;

然后,一旦设置了测试平台,请将其设置为最后一个beforeEach()内测试床正在使用的实际服务:

authService = TestBed.get(AuthService);

最后在测试中使用它来设置您要在.redirectUrl上进行的操作:

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

工作StackBlitz