Asynchronous 测试异步管道转换 上下文

Asynchronous 测试异步管道转换 上下文,asynchronous,angular,jasmine,angular2-testing,angular2-pipe,Asynchronous,Angular,Jasmine,Angular2 Testing,Angular2 Pipe,我有一个基本的PipeTransform,希望它是异步的。为什么?因为我有自己的i18n服务(由于解析、复数化和其他限制,我自己做了),它返回一个承诺: 这个管道工作得很好,因为唯一延迟的调用是第一个调用(I18N服务使用延迟加载,它只在找不到键的情况下加载JSON数据,因此基本上,第一个调用会延迟,其他调用是即时的,但仍然是异步的) 问题 我不知道如何使用Jasmine测试这个管道,因为它在一个组件中工作,我知道它可以工作,但这里的目标是使用Jasmine对它进行全面测试,这样我可以将它添加到

我有一个基本的
PipeTransform
,希望它是异步的。为什么?因为我有自己的i18n服务(由于解析、复数化和其他限制,我自己做了),它返回一个
承诺

这个管道工作得很好,因为唯一延迟的调用是第一个调用(I18N服务使用延迟加载,它只在找不到键的情况下加载JSON数据,因此基本上,第一个调用会延迟,其他调用是即时的,但仍然是异步的)

问题 我不知道如何使用Jasmine测试这个管道,因为它在一个组件中工作,我知道它可以工作,但这里的目标是使用Jasmine对它进行全面测试,这样我可以将它添加到CI例程中

上述测试:

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");
        })));
});
由于i18n服务提供的结果是异步的,因此返回的值在同步逻辑中未定义,因此失败

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

预期未定义为“测试值”


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

使用
@angular/core/testing
中的
fakeAsync
。它允许您调用
tick()
,这将等待所有当前排队的异步任务完成后再继续。这给人一种动作同步的错觉。在调用
tick()
之后,我们就可以编写我们的期望

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
<代码>异步允许继续测试,直到所有异步调用完成。比如说

it('..', async(() => {
  let service = new Servce();
  service.doSomething().then(result => {
    expect(result).toBe('hello');
  });
});
在非
async
测试中,预期永远不会发生,因为测试将在承诺的异步解析之前完成。通过调用
async
,测试被包装在一个区域中,该区域跟踪所有异步任务,并等待它们完成


当异步行为不在测试的控制范围内时(如在管道中进行的情况),请使用
fakeAsync
。在这里,我们可以通过调用
tick()
强制/等待它完成<代码>勾选也可以传递毫秒延迟,以便在需要时允许更多的时间传递


另一个选项是模拟服务并使其同步,如中所述。当进行单元测试时,如果您的测试中的组件依赖于服务中的大量逻辑,那么测试中的组件将受服务正常工作的支配,这有点违背了“单元”测试的目的。模拟在很多情况下都有意义。

另一个涉及的问题是管道的转换只调用一次,因此返回基本上总是未定义的。我通过在测试文件中创建一个递归方法修复了这个问题,该方法允许我调用管道转换,只要我没有定义结果,就可以使用maxium调用堆栈。
it('..', async(() => {
  let service = new Servce();
  service.doSomething().then(result => {
    expect(result).toBe('hello');
  });
});