Angular 튜토리얼

"/> Angular 튜토리얼

">

>웹 프론트엔드 >JS 튜토리얼 >Jasmine을 사용한 Angular 단위 테스트 소개

Jasmine을 사용한 Angular 단위 테스트 소개

青灯夜游
青灯夜游앞으로
2020-08-22 11:23:262806검색

이 기사에서는 Jasmine을 Angular 단위 테스트에 사용하는 방법을 설명합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

Jasmine을 사용한 Angular 단위 테스트 소개

다음은 단위 테스트를 거의 작성하지 않거나 전혀 작성하지 않은 사람들이 많은 개념적 문제를 모국어로 설명할 수 있고 Jasmine의 해당 방법과 결합하여 설명할 것이라는 가정하에 제가 준비한 것입니다.

1. 개념

Test Suite

Test Suite는 단순한 클래스라도 여러 개의 테스트 케이스를 갖기 때문에 이러한 테스트 케이스를 하나의 카테고리에 모아 놓은 것을 Test Suite라고 합니다.

Jasmine에서는 describe 전역 함수로 표현되는데 첫 번째 문자열 매개변수는 Suite의 이름이나 제목을 나타내는 데 사용되고 두 번째 메서드 매개변수는 Suite 코드를 구현하는 데 사용됩니다. describe 全局函数来表示,它的第一个字符串参数用来表示Suite的名称或标题,第二个方法参数就是实现Suite代码了。

describe('test suite name', () => {
});

Specs

一个Specs相当于一个测试用例,也就是我们实现测试具体代码体。

Jasmine 就是使用 it 全局函数来表示,和 describe 类似,字符串和方法两个参数。

而每个 Spec 内包括多个 expectation 来测试需要测试的代码,只要任何一个 expectation 结果为 false 就表示该测试用例为失败状态。

describe('demo test', () => {
    const VALUE = true;
    it('should be true', () => {
        expect(VALUE).toBe(VALUE);
    })
});

Expectations

断言,使用 expect 全局函数来表示,只接收一个代表要测试的实际值,并且需要与 Matcher 代表期望值

二、常用方法

Matchers

断言匹配操作,在实际值与期望值之间进行比较,并将结果通知Jasmine,最终Jasmine会判断此 Spec 成功还是失败。

Jasmine 提供非常丰富的API,一些常用的Matchers:

  • toBe() 等同 ===
  • toNotBe() 等同 !==
  • toBeDefined() 等同 !== undefined
  • toBeUndefined() 等同 === undefined
  • toBeNull() 等同 === null
  • toBeTruthy() 等同 !!obj
  • toBeFalsy() 等同 !obj
  • toBeLessThan() 等同 af9417e844a2af0db288e39505fc6b65
  • toEqual() 相当于 ==
  • toNotEqual() 相当于 !=
  • toContain() 相当于 indexOf
  • toBeCloseTo() 数值比较时定义精度,先四舍五入后再比较。
  • toHaveBeenCalled() 检查function是否被调用过
  • toHaveBeenCalledWith() 检查传入参数是否被作为参数调用过
  • toMatch() 等同 new RegExp().test()
  • toNotMatch() 等同 !new RegExp().test()
  • toThrow() 检查function是否会抛出一个错误

而这些API之前用 not 来表示负值的判断。

expect(true).not.toBe(false);

这些Matchers几乎可以满足我们日常需求,当然你也可以定制自己的Matcher来实现特殊需求。

Setup 与 Teardown

一份干将的测试代码很重要,因此我们可以将这些重复的 setup 与 teardown 代码,放在与之相对应的 beforeEachafterEach 全局函数里面。

beforeEach 表示每个 Spec 执行之前,反之。

describe('demo test', () => {
    let val: number = 0;
    beforeEach(() => {
        val = 1;
    });
    it('should be true', () => {
        expect(val).toBe(1);
    });
    it('should be false', () => {
        expect(val).not.toBe(0);
    });
});

数据共享

如同上面示例中,我们可以在每个测试文件开头、describe 来定义相应的变量,这样每个 it 内部可以共享它们。

当然,每个 Spec 的执行周期间也会伴随着一个空的 this 对象,直至 Spec 执行结束后被清空,利用 this 也可以做数据共享。

嵌套代码

有时候当我们对某个组件进行测试时,而这个组件会有不同状态来展示不同的结果,这个时候如果只用一个 describe 会显得不过优雅。

因此,嵌套 describe,会让测试代码、测试报告看起来更漂亮。

describe('AppComponent', () => {
    describe('Show User', () => {
        it('should be show panel.', () => {});
        it('should be show avatar.', () => {});
    });
    describe('Hidden User', () => { 
        it('should be hidden panel.', () => {});
    });
});

跳过测试代码块

需求总是三心二意的,但好不容易写好的测试代码,难道要删除吗?非也……

Suites 和 Specs 分别可以用 xdescribexit

describe('AppComponent', () => {
    let fixture: ComponentFixture<TestComponent>;
    let context: TestComponent;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [TestComponent]
        });
        fixture = TestBed.createComponent(TestComponent);
        context = fixture.componentInstance;
        // 监听onSelected方法
        spyOn(context, &#39;onSelected&#39;);
        fixture.detectChanges();
    });

    it(&#39;should be called [selected] event.&#39;, () => {
        // 触发selected操作

        // 断言是否被调用过
        expect(context.onSelected).toHaveBeenCalled();
    });
});

Specs

A Specs는 테스트를 위해 구현하는 특정 코드 본문인 테스트 사례와 동일합니다.

Jasmine은 describe와 유사하게 it 전역 함수를 문자열과 메소드라는 두 개의 매개변수와 함께 사용하여 표현합니다. 각 사양에는 테스트해야 하는 코드를 테스트하기 위한 여러 가지 기대 사항이 포함되어 있습니다. 기대 사항의 결과가 false인 경우에는 테스트 사례가 실패한 상태임을 의미합니다.

export class AppComponent {
  constructor(private _user: UserService) {}

  query() {
    this._user.quer().subscribe(() => {});
  }
}

🎜🎜Expectations🎜🎜🎜🎜expect 전역 함수를 사용하여 표현된 Assertions는 테스트할 🎜실제 값🎜의 대표만 수신하고, 🎜기대값🎜. 🎜🎜🎜🎜 2. 일반적으로 사용되는 방법🎜🎜🎜🎜🎜🎜Matchers🎜🎜🎜🎜매칭 연산을 수행하고, 실제 값과 예상 값을 비교하고, 결과를 Jasmine에 통보합니다. 마지막으로 이 Spec의 성공 여부를 Jasmine이 판단합니다. 아니면 실패합니다. 🎜🎜Jasmine은 매우 풍부한 API를 제공하며 일반적으로 사용되는 일부 일치 프로그램을 제공합니다. 🎜
  • toBe()===
  • toNotBe ()는 !==와 동일합니다.
  • toBeDefined()는 !== 정의되지 않음
  • toBeUndefine( )는 = == 정의되지 않음과 같습니다.
  • toBeNull()은 === null
  • toBeTruthy()와 같습니다. !!obj와 동일
  • toBeFalsy()는 !obj와 동일
  • toBeLessThan()은 와 동일 8e8c429444659efedfd555986d2ff5f4
  • toEqual()은 ==와 동일합니다. li>
  • toNotEqual()은 != code>와 동일합니다.
  • toContain()은 indexOf
  • toBeCloseTo(와 동일합니다. ) 정밀도를 정의하기 위해 수치를 비교할 때는 먼저 반올림한 후 비교합니다.
  • toHaveBeenCalled()는 함수가 호출되었는지 확인합니다.
  • toHaveBeenCalledWith()는 들어오는 매개변수가 매개변수로 호출되었는지 확인합니다.
  • toMatch()는 동일합니다. new RegExp().test()
  • toNotMatch()는 !new RegExp().test()
  • toThrow() 함수에서 오류가 발생하는지 확인
🎜이 API는 이전에 음수 값의 판단을 나타내기 위해 not을 사용했습니다. 🎜
it(&#39;should be get user list (async)&#39;, async(() => {
    // call component.query();
    fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(true).toBe(true);
    });
}));
🎜이러한 Matcher는 일상적인 요구 사항을 거의 충족할 수 있습니다. 물론 특별한 요구 사항에 맞게 자신만의 Matcher를 맞춤 설정할 수도 있습니다. 🎜🎜🎜🎜설정 및 해제🎜🎜🎜🎜가능한 테스트 코드는 매우 중요하므로 이러한 반복되는 설정 및 해제 코드를 내부의 해당 beforeEachafterEach에 넣을 수 있습니다. 글로벌 기능. 🎜🎜beforeEach는 각 사양이 실행되기 전을 의미하며 그 반대의 경우도 마찬가지입니다. 🎜
it(&#39;should be get user list (async)&#39;, fakeAsync(() => {
    // call component.query();
    tick();
    fixture.detectChanges();
    expect(true).toBe(true);
}));
🎜🎜🎜데이터 공유🎜🎜🎜🎜위의 예에서와 같이 각 테스트 파일 describe의 시작 부분에 해당 변수를 정의할 수 있습니다. > 내부적으로 공유할 수 있습니다. 🎜🎜물론 각 Spec 실행 주기에는 Spec 실행 후 지워질 때까지 빈 this 객체가 수반됩니다. this를 사용하여 데이터 공유도 수행할 수 있습니다. > . 🎜🎜🎜🎜중첩된 코드🎜🎜🎜🎜가끔 컴포넌트를 테스트할 때 컴포넌트의 상태가 달라서 다른 결과를 표시하는 경우가 있습니다. 이때 describe 하나만 사용하면 너무 우아해 보일 수 있습니다. . 🎜🎜따라서 describe를 중첩하면 테스트 코드와 테스트 보고서가 더욱 아름답게 보입니다. 🎜
it(&#39;async demo&#39;, (done: () => void) => {
    context.show().subscribe(res => {
        expect(true).toBe(true);
        done();
    });
    el.querySelected(&#39;xxx&#39;).click();
});
🎜🎜🎜테스트 코드 블록 건너뛰기🎜🎜🎜🎜요구는 언제나 반성인데 최종 작성된 테스트 코드는 삭제해야 할까요? 아니요...🎜🎜Suites 및 Specs는 각각 xdescribexit 전역 함수를 사용하여 이러한 테스트 코드 블록을 건너뛸 수 있습니다. 🎜🎜🎜🎜3. Angular 도구 세트와 협력🎜🎜🎜🎜🎜🎜Spy🎜🎜🎜

Angular的自定义事件实在太普遍了,但为了测试这些自定义事件,因此监控事件是否正常被调用是非常重要。好在,Spy 可以用于监测函数是否被调用,这简直就是我们的好伙伴。

以下示例暂时无须理会,暂且体验一下:

describe(&#39;AppComponent&#39;, () => {
    let fixture: ComponentFixture<TestComponent>;
    let context: TestComponent;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [TestComponent]
        });
        fixture = TestBed.createComponent(TestComponent);
        context = fixture.componentInstance;
        // 监听onSelected方法
        spyOn(context, &#39;onSelected&#39;);
        fixture.detectChanges();
    });

    it(&#39;should be called [selected] event.&#39;, () => {
        // 触发selected操作

        // 断言是否被调用过
        expect(context.onSelected).toHaveBeenCalled();
    });
});

异步支持

首先,这里的异步是指带有 Observable 或 Promise 的异步行为,因此对于组件在调用某个 Service 来异步获取数据时的测试状态。

假设我们的待测试组件代码:

export class AppComponent {
  constructor(private _user: UserService) {}

  query() {
    this._user.quer().subscribe(() => {});
  }
}

async

async 无任何参数与返回值,所有包裹代码块里的测试代码,可以通过调用 whenStable()所有待处理异步行为都完成后再进行回调;最后,再进行断言操作。

it(&#39;should be get user list (async)&#39;, async(() => {
    // call component.query();
    fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(true).toBe(true);
    });
}));

fakeAsync

如果说 async 还需要回调才能进行断点让你受不了的话,那么 fakeAsync 可以解决这一点。

it(&#39;should be get user list (async)&#39;, fakeAsync(() => {
    // call component.query();
    tick();
    fixture.detectChanges();
    expect(true).toBe(true);
}));

这里只是将回调换成 tick(),怎么样,是不是很酷。

Jasmine自带异步

如前面所说的异步是指带有 Observable 或 Promise 的异步行为,而有时候我们有些东西是依赖 setTimeout 或者可能是需要外部订阅结果以后才能触发时怎么办呢?

可以使用 done() 方法。

it(&#39;async demo&#39;, (done: () => void) => {
    context.show().subscribe(res => {
        expect(true).toBe(true);
        done();
    });
    el.querySelected(&#39;xxx&#39;).click();
});

四、结论

本章几乎所有的内容在Angular单元测试经常使用到的东西;特别是异步部分,三种不同异步方式并非共存的,而是需要根据具体业务而采用。否则,你会发现真TM难写单元测试。毕竟这是一个异步的世界。

自此,我们算是为Angular写单元测试打下了基础。后续,将不会再对这类基础进行解释。

happy coding!

相关教程推荐:angular教程

위 내용은 Jasmine을 사용한 Angular 단위 테스트 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제