我将如何为此功能编写单元测试?提交表单后,它将发送POST请求以获取登录令牌。通过令牌响应,它随后发送另一个请求以获取特定的用户详细信息。
功能如下:
// Log the user in and save the token, then get the details
onLoginSubmit() {
this.loggingIn = true;
// request the token then the details for the user based off the token
this.userService
.LoginUser(this.loginForm.value.username, this.loginForm.value.password)
.pipe(
tap(res => {
// console.log('Obtained Token:', res);
localStorage.setItem('login_token', res.token);
// this.utilityService.SetLocalStorage('login_token', res.token, 1, 'd');
}),
concatMap(() => this.userService.GetTokenDetails()),
)
.subscribe(
res => {
// console.log('Obtained User Data:', res);
localStorage.setItem('user', res.user);
// this.utilityService.SetLocalStorage('user', res.user, 1, 'd');
this.NavigateToRoute();
},
() => {
this.loggingIn = false;
},
);
}
以下是服务功能:
// logs in the user
LoginUser(email, password): Observable<any> {
return this.utilityservice.post('universal/login', { email, password }, this.utilityservice.GetHeaders());
}
// gets details of the current logged in user
GetTokenDetails() {
return this.utilityservice.get('universal/userAPI', { whoami: '' });
}
对于单元测试,我假设我需要创建一个模拟服务,其中这些函数将返回如下所示的有效响应:
// logs in the user
LoginUser(email, password): Observable<any> {
return { res: { token: 'test' } };
}
这是正确的方法还是我完全错误?同样,对于登录页面的E2E测试,我本质上是在每次测试中通过编写代码来模拟用户,该代码模拟单击表单按钮并输入值,然后检查以确保获得有效的响应,或者我是否使其复杂化? >
答案 0 :(得分:0)
大多数测试库(如Jasmine或Mocha)将包含模拟工具,以帮助您编写这些测试。否则,您将走在正确的轨道上。
您的单元测试不应测试服务,而只能测试被测试的代码,在这种情况下,该代码似乎是组件。
我个人在规范中使用RxJs库-因此我可以创建一个类似的模拟类,并提供一个实例:
class MockUserService {
public loginSubject = new Subject();
public loginCalls = [];
// logs in the user
public LoginUser(email, password): Observable<any> {
this.loginCalls.push({ email, password });
return this.loginSubject.asObservable();
}
}
这样,在我的规格书中的其他地方,我可以做这样的事情:
it('calls login on the user service', () => {
expect(mockUserService.loginCalls.length > 0).toBe(true);
});
it('sets value on local storage', fakeAsync(() => {
mockUserService.loginSubject.next({ res: { token: 'test-token' }});
flushMicrotasks();
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('login_token', 'test-token', 1, 'd');
}));
通常使用Jasmine编写规范,因此您实际上可以像这样进行设置(此处的示例规范使用jasmine的结构)。
loginSubject = new Subject();
const mockUserService = jasmine.createSpyObj('UserService', ['LoginUser']);
mockUserService.LoginUser.and.returnValue(loginSubject.asObservable());
要进行更多设置才能使其正常运行;依赖注入是很棒的,因为它使您能够编写规范,但是它也增加了一些样板。我通常在顶部配置测试,如下所示:
describe('LoginComponent', () => {
let loginSubject: Subject<any>;
let mockLocalStorage: jasmine.SpyObj<LocalStorageService>;
let fixture: ComponentInstance<LoginComponent>;
beforeEach(() => {
loginSubject = new Subject();
const mockUserService = jasmine.createSpyObj('UserService', ['LoginUser']);
mockUserService.LoginUser.and.returnValue(loginSubject.asObservable());
mockLocalStorage = jasmine.createSpyObj('LocalStorage', ['setItem']);
TestBed.configureTestingModule({
declarations: [LoginComponent],
providers: [
{ provide: UserService, useValue: mockUserService },
{ provide: LocalStorageService, useValue: mockLocalStorage }
]
});
fixture = TestBed.createComponent(LoginComponent);
});
it('calls login on the user service', () => {
expect(mockUserService.loginCalls.length > 0).toBe(true);
});
it('sets value on local storage', fakeAsync(() => {
loginSubject.next({ res: { token: 'test-token' }});
flushMicrotasks();
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('login_token', 'test-token', 1, 'd');
}));
});
我正在做大量假设(例如您已经以某种方式内联了模板,否则在创建组件时需要异步beforeEach)。
最后,您可能应该在这里查看手册:https://angular.io/guide/testing
答案 1 :(得分:0)
您问了2个问题;关于端到端测试。假设您必须登录,则登录页面会针对其他所有规格进行测试。我的配置是使用我的注册页面创建一个新用户,注销并使用这些凭据登录。之后,我继续进行其他测试。这样一来,我避免为测试设置很多罐装数据。
确实,对于e2e更改而言,重要的是根据应用程序的需求。我会挑选一些您最重要的页面,并确保它们被e2e覆盖,因为e2e规范1.)构建成本高昂,并且2.)可能存在问题。不过,登录页面几乎始终是“对于应用程序最重要的部分”的一部分。