代码之家  ›  专栏  ›  技术社区  ›  Coderer

在超时之前,预计jasmine Spy将被称为“最终”

  •  0
  • Coderer  · 技术社区  · 4 年前

    我最近写了很多异步单元测试,结合了Angular的 fakeAsync ,从返回Promises async 测试身体功能,茉莉花 done 回调等。一般来说,我能够以一种完全确定的方式使一切正常工作。

    我的代码的一些部分与第三方库的交互方式非常复杂,很难模仿。我无法找到一种方法来挂接一个事件或生成一个Promise,保证在这个库完成后台工作后解决,所以目前我的测试只能使用 setTimeout :

    class MyService {
      public async init() {
        // Assume library interaction is a lot more complicated to replace with a mock than this would be
        this.libraryObject.onError.addEventListener(err => {
          this.bannerService.open("Load failed!" + err);
        });
        // Makes some network calls, etc, that I have no control over
        this.libraryObject.loadData();
      }
    }
    
    it("shows a banner on network error", async done => {
        setupLibraryForFailure();
        await instance.init();
    
        setTimeout(() => {
            expect(banner.open).toHaveBeenCalled();
            done();
        }, 500);  // 500ms is generally enough... on my machine, probably
    });
    

    这让我很紧张,尤其是魔术数字 setTimeout 。它的扩展性也很差,因为我敢肯定500毫秒比我完成的任何其他测试都要长得多。

    我想我想做的是,能够告诉贾斯敏去投票 banner.open 间谍,直到它被调用,或者直到测试超时并且测试失败。然后,一旦错误处理程序被触发并完成,测试就会注意到。是否有更好的方法,或者这是一个好主意?这是我没有看到的某个内置模式吗?

    0 回复  |  直到 4 年前
        1
  •  1
  •   AliF50    4 年前

    我想你可以利用 callFake ,基本上是在调用另一个函数后调用该函数。

    大致如下:

    it("shows a banner on network error", async done => {
        setupLibraryForFailure();
        // maybe you have already spied on banner open so you have to assign the previous
        // spy to a variable and use that variable for the callFake
        spyOn(banner, 'open').and.callFake((arg: string) => {
          expect(banner.open).toHaveBeenCalled(); // maybe not needed because we are already doing callFake
          done(); // call done to let Jasmine know you're done
        });
        await instance.init();
    });
    

    我们正在banner.open上设置一个间谍,当它被调用时,它将使用callFake调用回调函数,我们在这个回调函数中调用done,让Jasmine知道我们的断言已经完成。