【问题标题】:Angular 5: Testing a service using windowAngular 5:使用窗口测试服务
【发布时间】:2018-01-09 09:39:05
【问题描述】:

我有一个服务,它有一个检查可用浏览器配额存储并返回 Observable 的方法:

import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";

@Injectable()
export class StorageService {
    hasAvailableStorage(): Observable<boolean> {
        const nav: any = navigator;

        return Observable.create(observer => {
            nav.webkitTemporaryStorage.queryUsageAndQuota(
                (usedBytes, grantedBytes) => {
                    observer.next(usedBytes <= grantedBytes * 0.8);
                }
            );
        });
    }
}

我想对该服务进行单元测试,但我不知道如何在测试中访问窗口或模拟窗口/webkitTemporaryStorage。

我尝试了以下方法,但是它给出了一个错误,即 window.webkitTemporaryStorage 是只读的并且无法分配给:

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

import { StorageService } from "./storage.service";

@Injectable()
class MockWebkitTemporaryStorage {
    queryUsageAndQuota(cb) {
        return cb(10, 15);
    }
}

describe("storage.service", () => {
    let service: StorageService;

    const nav: any = window.navigator;
    nav.webkitTemporaryStorage = MockWebkitTemporaryStorage;

    beforeAll(() => {
        service = new StorageService();
    });

    it("should return the result of hasAvailableStorage()", () => {
        const result = service.hasAvailableStorage();
        expect(result).toBeDefined();
    });
});

我预计我最终必须在窗口导航器/queryUsageAndQuota 上使用某种间谍,但我看不出我应该如何设置或完成测试才能做到这一点。如果有人可以帮助我并详细提供一些示例,那就太好了! :)

EDIT 更改测试(在 cmets 之后):

describe("storage.service", () => {
    let service: StorageService;

    beforeAll(() => service = new StorageService());

    it("should return the result of hasAvailableStorage()", () => {
        const spy = spyOn(navigator["webkitTemporaryStorage"], "queryUsageAndQuota").and.callFake(MockWebkitTemporaryStorage);
        const result = service.hasAvailableStorage();
        expect(spy).toHaveBeenCalled();
        expect(result).toBeDefined();
    });
});

此后,测试失败并出现错误:'Expected spy queryUsageAndQuota to have been called。'

【问题讨论】:

  • 快速提问:这些导航器方法是原生的,还是您正在创建它们?
  • 这些是本机方法,只是在服务中调用。

标签: angular unit-testing angular5


【解决方案1】:

在您回答我的评论后,这是我的回答:您没有正确测试它

由于这些方法是本机方法(我假设您不会覆盖),因此您不应该测试它们是否有效。它们是用来工作的。您应该测试的是它们是否被调用

你的测试应该是这样的:

describe("storage.service", () => {
    let service: StorageService;

    beforeAll(() => service = new StorageService());

    it("should return the result of hasAvailableStorage()", () => {
        const spy = spyOn(navigator["webkitTemporaryStorage"], "queryUsageAndQuota").and.callFake(MockWebkitTemporaryStorage);
        service.hasAvailableStorage().subscribe(() => {
            expect(spy).toHaveBeenCalled();
        });
    });
});

现在你正在测试导航器是否调用了正确的函数,你模拟这个函数,返回一些东西,你期望这个函数被调用。

这应该可以解决问题。

【讨论】:

  • 用你的代码给出:“(TS)属性'webkitTemporaryStorage'在导航器类型上不存在”,所以我在spyOn 和期望调用。那么输出错误是:Expected spy queryUsageAndQuota to has been called, and the test is failed.
  • 我刚刚检查了自己:导航器对象中不存在这些方法(它们确实存在,但已被弃用)。也许你应该使用别的东西?否则,如果您想使用它,也许您应该重新创建它(使用虚拟存根)以查看它们是否被调用。你知道怎么做吗?
  • 不,我不知道该怎么做。那和嘲讽一样吗?
  • 几乎 :) 在一行中:navigator.webkitTemporaryStorage = function() { return {queryUsageAndQuota: (usedBytes, grantedBytes) =&gt; {}}; } 这将创建虚拟函数并(通常)摆脱你的错误
  • 然后我得到与我开始时相同的错误:“TypeError:无法分配给对象'[object Navigator]'的只读属性'webkitTemporaryStorage'”。我将您的 oneliner 更改为两行: const nav: any = navigator; nav.webkitTemporaryStorage = () => ({ queryUsageAndQuota: (usedBytes,grantBytes) => {} });,并在测试中的 beforeAll 之前添加。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-09
  • 2014-11-12
  • 1970-01-01
  • 2023-01-30
相关资源
最近更新 更多