如何使用 jasmine 为注销服务正确编写单元测试?

时间:2021-03-01 14:24:21

标签: angular jasmine

我对单元测试还是个新手,所以我想知道是否有人帮助我完成这个小任务。 我在茉莉花中使用 angular 8。

这是我的注销服务:

import {Injectable} from '@angular/core';

@Injectable({
        providedIn: 'root'
})
export class LogoutService {
    logout() {
        const {protocol, hostname, port: locationPort} = window.location;
        const port = locationPort ? `:${locationPort}` : '';
        window.location.href =
                `/oauth/logout?redirect=${protocol}//${hostname}${port}`;
    }
}

这是我正在尝试的测试:

import { LogoutService } from './logout.service';

describe('LogoutService', () => {
    let service;
    beforeEach(() => {
        service = new LogoutService();
    });
    it('should run #logout()', async () => {
        let path = '/oauth/logout?redirect'
        service.logout();
        expect(window.location.href).toEqual(jasmine.objectContaining(path))

    });
});

到目前为止,我正在尝试测试 Windows 位置是否具有协议、主机名和端口。

提前致谢。

1 个答案:

答案 0 :(得分:0)

首先,您似乎使用了错误的函数:根据官方文档,jasmine.objectContaining 处理的不是字符串而是 jsons。 toContain 对您来说是更好的选择。

其次,您的目标是测试 window.location 是否包含协议等数据。因此检查“/oauth/logout?redirect”(您的路径变量)不是解决方案。

第三,您的服务设计表明 window.location 既用作输入(更准确的外部依赖)又用作测试的输出,而且您似乎将全局变量 locationPort 作为另一个输入。为了实现有用的测试,您应该控制您的输入(控制输入可以简单地意味着重新分配 window.location,但这可能会出现问题;但是,可以通过重新设计注销方法来解决此问题)。

话虽如此,你可以尝试这样的事情:

logout(wl: any) {
  const {protocol, hostname, port: locationPort} = wl;
  const port = locationPort ? `:${locationPort}` : '';
  return `/oauth/logout?redirect=${protocol}//${hostname}${port}`;
}
it('should run #logout()', async () => {
  const wl = { ...window.location, protocol: 'some-protocol', hostname: 'some-hostname' };
  locationPort = 4200;
  const href = service.logout(wl);
  expect(href).toContain('some-protocol');
  expect(href).toContain('some-hostname');
  expect(href).toContain('4200');
  // or
  // expect(href).toContain(`some-protocol//some-hostname:4200`);
});

(当然,在您的应用程序中,您必须将注销方法的返回值分配给 window.location.href)

我对注销方法所做的更改不仅仅是技术上的更改;它反映了单元测试如何让我们重新思考我们的代码设计。