Kiểm tra Angular 2 - Lệnh gọi hàm không đồng bộ - khi nào sử dụng


86

Khi nào bạn sử dụng chức năng không đồng bộ trong TestBed khi kiểm tra trong Angular 2?

Khi nào bạn sử dụng cái này?

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

Và khi nào bạn sử dụng cái này?

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

Bất cứ ai có thể khai sáng cho tôi về điều này?

Câu trả lời:


96

asyncsẽ không cho phép thử nghiệm tiếp theo bắt đầu cho đến khi asynckết thúc tất cả các nhiệm vụ của nó. Điều gì asynclà bọc lệnh gọi lại trong một Vùng, nơi tất cả các tác vụ không đồng bộ (ví dụ setTimeout) được theo dõi. Khi tất cả các tác vụ không đồng bộ đã hoàn tất, thì các tác vụ sẽ hoàn asyncthành.

Nếu bạn đã từng làm việc với Jasmine bên ngoài Angular, bạn có thể đã thấy doneđược chuyển đến cuộc gọi lại

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

Đây, đây là Jasmine bản địa, nơi chúng tôi nói với Jasmine rằng bài kiểm tra này sẽ trì hoãn việc hoàn thành cho đến khi chúng tôi gọi điện done(). Nếu chúng tôi không gọi done()và thay vào đó đã gọi :

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

Kiểm tra sẽ hoàn thành ngay cả trước kỳ vọng, vì lời hứa sẽ giải quyết sau khi kiểm tra kết thúc thực hiện các tác vụ đồng bộ.

Với Angular (trong môi trường Jasmine), Angular sẽ thực sự gọi donephía sau khi chúng ta sử dụng async. Nó sẽ theo dõi tất cả các tác vụ không đồng bộ trong Zone và khi tất cả chúng hoàn thành, donenó sẽ được gọi ở hậu trường.

Trong trường hợp cụ thể của bạn với TestBedcấu hình, bạn sẽ sử dụng điều này nói chung khi bạn muốn compileComponents. Tôi hiếm khi gặp phải tình huống mà tôi phải gọi nó theo cách khác

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

Khi kiểm tra một thành phần sử dụng templateUrl(nếu bạn không sử dụng webpack), thì Angular cần thực hiện một yêu cầu XHR để lấy mẫu, vì vậy việc biên dịch thành phần sẽ không đồng bộ. Vì vậy, chúng ta nên đợi cho đến khi nó giải quyết trước khi tiếp tục thử nghiệm.


Câu trả lời tuyệt vời @peeskillet. Chỉ để đảm bảo rằng tôi hiểu nó: Khi bạn có một mẫu nội tuyến, asynckhông cần thiết. Khi bạn đang sử dụng templateUrl, nó là. Tuy nhiên, việc bao gồm asyncsẽ không "phá vỡ" một thành phần mẫu nội tuyến. Bạn có nghĩ rằng có an toàn không khi nói rằng người ta có thể mặc định sử dụng asynccho mọi bài kiểm tra?
vince

2
@vincecampanale TemplateUrl chỉ quan trọng trong quá trình cấu hình ở beforeEach. Trong trường hợp đó bạn cần gọi compileComponents. Nó không liên quan gì đến việc sử dụng asynctrong mỗi bài kiểm tra nếu đó là những gì bạn đang yêu cầu. Theo như được an toàn (khi bạn nên gọi compileComponents), xem Khi nào tôi phải compileComponents cuộc gọi
Paul Samsotha

2
@vincecampanale Không phải lúc nào bạn cũng muốn nó được gọi trước khi kiểm tra. Đôi khi bạn có thể muốn gọi nó sau khi bạn thực hiện một số khởi tạo. Bạn cần hiểu nó thực sự có tác dụng gì. Mặc dù vậy, hầu hết thời gian nó sẽ ổn. Nhưng cá nhân tôi không thích việc họ tự đưa ra quyết định đó. Nhưng tôi thấy rất nhiều người gặp phải vấn đề mà họ quên không gọi nó, và họ tự hỏi tại sao cái gì đó không hoạt động. Vì vậy, có lẽ tốt hơn là họ tạo ra cuộc gọi. Các vị trí có thể gây tranh cãi, nhưng ít nhất họ gọi nó
Paul Samsotha

2
@vincecampanale Nói chung khi bạn muốn hiển thị (được) hiển thị là lúc bạn nên gọi nó. Ví dụ Create Component -> render view. Nhưng nếu bạn muốn khởi tạo một cái gì đó trước tiên như Create Component -> thay đổi giá trị trong thành phần được sử dụng để kết xuất -> hiển thị kết xuất. Đó là những gì tôi có nghĩa là bởi có thể bạn muốn khởi tạo một cái gì đó đầu tiên
Paul Samsotha

1
Oh, và một điều nữa. Lần đầu tiên bạn gọi nó, là khi ngOnInitthành phần được gọi. Đôi khi điều này quan trọng khi kiểm tra
Paul Samsotha

26

Khi bạn thực hiện một cuộc gọi không đồng bộ trong thử nghiệm của mình, chức năng kiểm tra thực tế sẽ được hoàn thành trước khi hoàn tất cuộc gọi không đồng bộ. Khi bạn cần xác minh một số trạng thái khi cuộc gọi hoàn thành (thường là như vậy) thì khung kiểm tra sẽ báo cáo kiểm tra là đã hoàn thành trong khi vẫn có công việc không đồng bộ đang diễn ra.

Với việc sử dụng, async(...)bạn yêu cầu khung thử nghiệm đợi cho đến khi hoàn thành lời hứa trả về hoặc có thể quan sát được trước khi coi thử nghiệm là hoàn thành.

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);
  });
}));

Mã được chuyển tới then(...)sẽ được thực thi sau khi bản thân chức năng kiểm tra hoàn thành. Với việc async()bạn làm cho khung kiểm tra nhận thức được, rằng nó cần phải đợi các lời hứa và khả năng quan sát hoàn thành trước khi coi kiểm tra là hoàn thành.

Xem thêm

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.