Angular 2 Testing - вызов функции Async - когда использовать

86

Когда вы используете функцию async в TestBed при тестировании в Angular 2?

Когда вы это используете?

 beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [MyModule],
            schemas: [NO_ERRORS_SCHEMA],
        });
    });

А когда ты этим пользуешься?

beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [MyModule],
        schemas: [NO_ERRORS_SCHEMA],
    });
}));

Может ли кто-нибудь просветить меня по этому поводу?

xiotee
источник

Ответы:

95

asyncне позволит начать следующий тест, пока он не завершит asyncвсе свои задачи. Что asyncделает, так это переносит обратный вызов в Зону, где setTimeoutотслеживаются все асинхронные задачи (например ). Как только все асинхронные задачи завершены, asyncзавершается.

Если вы когда-либо работали с Jasmine вне Angular, возможно, вы видели, doneкак передается обратный вызов

it('..', function(done) {
  someAsyncAction().then(() => {
    expect(something).toBe(something);
    done();
  });
});

Здесь это родной Jasmine, где мы говорим Jasmine, что этот тест должен отложить выполнение до тех пор, пока мы не вызовем done(). Если бы мы не позвонили, done()а сделали это:

it('..', function() {
  someAsyncAction().then(() => {
    expect(something).toBe(something);
  });
});

Тест завершится даже раньше, чем ожидалось, потому что обещание разрешается после того, как тест завершит выполнение синхронных задач.

С Angular (в среде Jasmine) Angular фактически будет вызывать doneза кулисами, когда мы используем async. Он будет отслеживать все асинхронные задачи в Зоне, и когда они все doneбудут завершены, будет вызываться за кулисами.

В вашем конкретном случае с TestBedконфигурацией вы обычно используете это, когда хотите compileComponents. Я редко сталкиваюсь с ситуацией, в которой мне пришлось бы назвать это иначе

beforeEach(async(() => {
   TestBed.configureTestingModule({
     declarations: [MyModule],
     schemas: [NO_ERRORS_SCHEMA],
   })
   .compileComponent().then(() => {
      fixture = TestBed.createComponent(TestComponent);
   });
}));

При тестировании компонента, который использует templateUrl(если вы не используете webpack), Angular необходимо сделать запрос XHR для получения шаблона, поэтому компиляция компонента будет асинхронной. Поэтому мы должны дождаться разрешения, прежде чем продолжить тестирование.

Пол Самсота
источник
Отличный ответ @peeskillet. Просто чтобы убедиться, что я это понимаю: когда у вас есть встроенный шаблон, в asyncэтом нет необходимости. Когда вы используете templateUrl, это так. Однако включение asyncне "сломает" компонент встроенного шаблона. Как вы думаете, можно ли с уверенностью сказать, что можно просто использовать asyncпо умолчанию для каждого теста?
Vince
2
@vincecampanale TemplateUrl имеет значение только во время настройки в beforeEach. В таком случае вам нужно позвонить compileComponents. Это не имеет ничего общего с использованием asyncв каждом тесте, если вы об этом спрашиваете. Что касается безопасности (когда вам следует позвонить compileComponents), см. Когда я должен вызывать compileComponents
Пол Самсота
2
@vincecampanale Не всегда нужно вызывать его перед тестом. Иногда вы можете захотеть вызвать его после некоторой инициализации. Вам нужно понять, что на самом деле делает вызов. Однако в большинстве случаев все должно быть в порядке. Но мне лично не нравится, что они взяли на себя это решение. Но я вижу, что многие люди сталкиваются с проблемой, когда забывают ее назвать, и задаются вопросом, почему что-то не работает. Так что, может быть, им лучше сделать звонок. Местоположение может быть спорным, но, по крайней мере, они его называют
Пол Самсота
2
@vincecampanale Обычно, когда вы хотите, чтобы представление (пере) рендерилось, вы должны его вызвать. Например, Create Component -> render view. Но если вы хотите сначала инициализировать что-то вроде Create Component -> измените значение в компоненте, который используется для визуализации -> render view. Вот что я имею в виду,
говоря,
1
Да, и еще одна вещь. В первый раз вы вызываете его, когда ngOnInitвызывается компонент. Иногда это имеет значение при тестировании
Пол Самсота
26

Когда вы выполняете асинхронный вызов в своем тесте, фактическая функция тестирования завершается до завершения асинхронного вызова. Когда вам нужно проверить какое-либо состояние, когда вызов был завершен (что обычно бывает), тогда тестовая среда сообщит, что тест завершен, пока еще продолжается асинхронная работа.

Используя using, async(...)вы указываете среде тестирования дождаться завершения обещания возврата или наблюдаемого, прежде чем рассматривать тест как завершенный.

it('should show quote after getQuote promise (async)', async(() => {
  fixture.detectChanges();

  fixture.whenStable().then(() => { // wait for async getQuote
    fixture.detectChanges();        // update view with quote
    expect(el.textContent).toBe(testQuote);
  });
}));

Код, переданный в, then(...)будет выполнен после завершения самой тестовой функции. С помощью async()вы сообщаете платформе тестирования, что ей нужно дождаться завершения обещаний и наблюдаемых, прежде чем рассматривать тест как завершенный.

Смотрите также

Гюнтер Цохбауэр
источник