测试异步PipeTransform [英] Test an async PipeTransform

查看:210
本文介绍了测试异步PipeTransform的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基本的 PipeTransform ,期望它是异步的。为什么?因为我有自己的i18n服务(因为解析,复数和其他约束,我自己做)并返回 Promise< string>

I have a basic PipeTransform, expect the fact that it is async. Why? because I have my own i18n service (because of parsing, pluralization and other constraints, I did my own) and it returns a Promise<string>:

@Pipe({
    name: "i18n",
    pure: false
})
export class I18nPipe implements PipeTransform {

    private done = false;

    constructor(private i18n:I18n) {
    }

    value:string;

    transform(value:string, args:I18nPipeArgs):string {
        if(this.done){
            return this.value;
        }
        if (args.plural) {
            this.i18n.getPlural(args.key, args.plural, value, args.variables, args.domain).then((res) => {
                this.value = res;
                this.done = true;
            });
        }
        this.i18n.get(args.key, value, args.variables, args.domain).then((res) => {
            this.done = true;
            this.value = res;
        });
        return this.value;
    }
}

此管道效果很好,因为唯一的延迟呼叫是第一个( I18nService 使用延迟加载,只有在未找到密钥时才加载JSON数据,所以基本上,第一个调用将被延迟,其他调用将是即时但仍然异步)。

This pipe works well, because the only delayed call is the very first one (the I18nService uses lazy loading, it loads JSON data only if the key is not found, so basically, the first call will be delayed, the other ones are instant but still async).

我无法弄清楚如何使用<测试此管道code> Jasmine ,因为它在我知道它可以工作的组件内部工作,但这里的目标是使用jasmine进行全面测试,这样我就可以将它添加到CI例程中。

I can't figure out how to test this pipe using Jasmine, since it is working inside a component I know it works, but the goal here is to get this fully tested using jasmine, this way I can add it to a CI routine.

以上测试:

describe("Pipe test", () => {

        it("can call I18n.get.", async(inject([I18n], (i18n:I18n) => {
            let pipe = new I18nPipe(i18n);
            expect(pipe.transform("nope", {key: 'test', domain: 'test domain'})).toBe("test value");
        })));
});

失败,因为 I18nService 是异步,返回值在同步逻辑中未定义。

Fails because since the result given by the I18nService is async, the returned value is undefined in a sync logic.


I18n管道测试可以调用I18n.get。 FAILED

I18n Pipe test can call I18n.get. FAILED

预期未定义为'测试值'。

Expected undefined to be 'test value'.

编辑:一种方法是使用 setTimeout 但我想要一个更漂亮的解决方案,以避免添加 setTimeout(myAssertion,100)无处不在。

One way to do it would be to use setTimeout but I want a prettier solution, to avoid adding setTimeout(myAssertion, 100) everywhere.

推荐答案

fakeAsync > @角/型芯/测试。它允许您调用 tick(),它将等待所有当前排队的异步任务完成后再继续。这给出了同步动作的错觉。在致电 tick()之后,我们可以写出我们的预期。

Use fakeAsync from @angular/core/testing. It allows you to call tick(), which will wait for all currently queued asynchronous tasks to complete before continuing. This gives the illusion of the actions being synchronous. Right after the call to tick() we can write our expectations.

import { fakeAsync, tick } from '@angular/core/testing';

it("can call I18n.get.", fakeAsync(inject([I18n], (i18n:I18n) => {
  let pipe = new I18nPipe(i18n);
  let result = pipe.transform("nope", {key: 'test', domain: 'test domain'});
  tick();
  expect(result).toBe("test value");
})));

那么我们何时应该使用 fakeAsync 以及何时使用我们应该使用 async 吗?这是我经常使用的经验法则(大部分时间)。当我们在内部进行异步调用时,我们应该使用 async async 允许测试继续,直到所有异步调用完成。例如

So when should we use fakeAsync and when should we use async? This is the rule of thumb that I go by (most of the time). When we are making asynchronous calls inside the test, this is when we should use async. async allows to test to continue until all asynchronous calls are complete. For example

it('..', async(() => {
  let service = new Servce();
  service.doSomething().then(result => {
    expect(result).toBe('hello');
  });
});

在非 async 测试中,期望永远不会发生,因为测试将在promise的异步解析之前完成。通过调用 async ,测试将被包装在一个区域中,该区域会跟踪所有异步任务,并等待它们完成。

In a non async test, the expectation would never occur, as the test would complete before the asynchronous resolution of the promise. With the call to async, the test gets wrapped in a zone, which keeps track of all asynchronous tasks, and waits for them to complete.

当异步行为超出测试控制范围时,使用 fakeAsync (就像在你的情况下正在进行管道)。在这里我们可以通过调用 tick()来强制/等待它完成。 tick 也可以传递毫秒延迟,以便在需要时允许更多时间通过。

Use fakeAsync when the asynchronous behavior is outside the control of the test (like in your case is going on in the pipe). Here we can force/wait for it to complete with the call to tick(). tick can also be passed a millisecond delay to allow more time to pass if needed.

另一种选择是模拟服务并使其同步,如这篇文章。在单元测试时,如果测试中的组件依赖于服务中的重逻辑,则测试中的组件受该服务正常工作的支配,这有点违背了单元测试的目的。在很多情况下,模拟很有意义。

Another option is to mock the service and make it synchronous, as mentioned in this post. When unit testing, if your components in test are dependent on heavy logic in the service, then the component in test is at the mercy of that service working correctly, which kinda defeats the purpose of a "unit" test. Mocking makes sense in a lot of cases.

这篇关于测试异步PipeTransform的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆