angular指令和管道_Angular单元测试开发人员指南—第2部分(服务,管道,指令)

angular指令和管道

Explore how to write test cases for shared services, Http services, pipes, and attribute directives in Angular.

探索如何在Angular中为共享服务,Http服务,管道和属性指令编写测试用例。

If you are new to unit testing and want to know how to start writing test cases, check out part 1 of this series, Developer’s guide to Unit Testing in Angular — Part 1.

如果您不熟悉单元测试,并且想知道如何开始编写测试用例,请查看本系列的第1部分,即Angular单元测试开发人员指南-第1部分

In this part, we’ll be covering a few points:

在这一部分中,我们将介绍以下几点:

  1. Testing Shared Services

    测试共享服务
  2. Testing Http Services

    测试Http服务
  3. Testing Pipes

    测试管
  4. Testing Attribute Directives

    测试属性指令

测试共享服务 (Testing Shared Services)

Shared services are used for sharing data between sibling components. Let’s create a shared service for users’ data, namely share-data-service.spec.ts.

共享服务用于在兄弟组件之间共享数据。 让我们为用户数据创建一个共享服务,即share-data-service.spec.ts。

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';@Injectable({
providedIn: 'root'
})export class ShareDataService {
userData: BehaviorSubject<any> = new BehaviorSubject(undefined);constructor() { }public setUser(user: any) {
this.userData.next(user);
}public getUser(): Observable<any> {
return this.userData.asObservable();
}
}

Let’s create test cases for this simple shared service.

让我们为这个简单的共享服务创建测试用例。

import { TestBed, async } from '@angular/core/testing';
import { ShareDataService } from './share-data.service';describe('ShareDataService', () => {
let store: ShareDataService
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ ShareDataService ],
})
store = TestBed.get(ShareDataService);
});it('should set User\'s data', async(() => {
const mockData = [{
"firstname": "Gurseerat",
"lastname": "Kaur",
"id": 1,
"dob": "11-02-1994"
}]

store.setUser(mockData);
store.getUser().subscribe(res => {
expect(res).toBe(mockData);
});
}));
});

Let’s see what is happening here:

让我们看看这里发生了什么:

  1. BehaviorSubject is used to emit the current value to the new subscribers.

    BehaviorSubject用于将当前值发送给新订户。

  2. Configure a unit testing environment for your service using TestBed.

    使用TestBed为您的服务配置单元测试环境。

  3. Pass your mock data as an argument in the setUser() method and subscribe to the getUser() method expecting that the response will be the same as mock data.

    将模拟数据作为参数传递给setUser()方法,并订阅getUser()方法,以期望响应与模拟数据相同。
  4. We’ll use async here for asynchronous tests.

    在这里,我们将使用async进行异步测试。

测试Http服务 (Testing Http Services)

Services are mostly used for fetching data using Http request and then components use them for displaying that data.

服务主要用于通过Http请求获取数据,然后组件将其用于显示该数据。

Suppose you have a service user.service.ts

假设您有一个服务user.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';@Injectable({
providedIn: 'root'
})export class UserService { public apiUrl = 'path/to/your/api'; constructor(private http: HttpClient) { } // Http request with GET method
fetchUsers() {
return this.http.get<any>(this.apiUrl);
}
}

Let’s first set up our service as we have a dependency here on HttpClient in user.service.ts

首先设置服务,因为我们在user.service.ts中HttpClient有依赖关系

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { UserService } from './web.service';describe('UserService', () => {
let service: UserService;
let httpTestingController: HttpTestingController; beforeEach(() => {
TestBed.configureTestingModule({
providers: [ UserService ],
imports: [ HttpClientTestingModule ]
}) service = TestBed.get(UserService);
httpTestingController = TestBed.get(HttpTestingController);
}); afterEach(() => {
httpTestingController.verify();
});
});

Let’s break this down and try to understand what is happening over here:

让我们分解一下,尝试了解这里发生的事情:

  1. HttpClientTestingModule and HttpTestingController are used to mock the Http requests to the backend and flush those requests.

    HttpClientTestingModuleHttpTestingController用于模拟对后端的Http请求并刷新这些请求。

  2. We’ll add all the dependencies and providers in TestBed.

    我们将在TestBed中添加所有依赖项和提供程序。
  3. verify() method of HttpTestingController instance will verify that no unmatched requests are outstanding and will throw an error indicating the requests that were not handled. We’ll add it in afterEach so that it is executed after every test case.

    HttpTestingController实例的verify()方法 将验证没有未匹配的请求是未解决的,并且将引发错误,指示未处理的请求。 我们将其添加到afterEach中,以便在每个测试用例之后执行它。

Let’s write test cases for fetchUsers() function.

让我们为fetchUsers()函数编写测试用例。

beforeEach(() => {
const mockData = {
"status": "success",
"data": [{
"firstname": "Gurseerat",
"lastname": "Kaur",
"id": 1,
"dob": "11-02-1994"
},
{
"firstname": "John",
"lastname": "Doe",
"id": 2,
"dob": "22-09-1994"
}]
}
})it('should check api response is VALID', () => {
service.fetchUsers().subscribe(res => {
expect(res).toEqual(mockData);
})const req = httpTestingController.expectOne(service.apiUrl);
expect(req.request.method).toBe('GET');

expect(

})

Few points to note about what’s going on here:

关于这里发生的事情,有几点要注意:

  1. We’ve added mock data in beforeEach so that we can use the same variable in all the specs that follow in this describe block.

    我们在beforeEach中添加了模拟数据,以便我们可以在此describe块中遵循的所有规范中使用相同的变量。

  2. Next, we’ll call fetchUsers() function, subscribe to its response, and expect the observable response is the same as mock data.

    接下来,我们将调用fetchUsers()函数,订阅其响应,并期望可观察到的响应与模拟数据相同。

  3. We’ll then use HttpTestingController and expect that only one request was made to the API.

    然后,我们将使用HttpTestingController并期望仅对该API发出一个请求。
  4. We can then make any number of assertions. Here, we are expecting that the request method is GET, the request is not canceled and the response type is JSON.

    然后,我们可以进行任意数量的断言。 在这里,我们期望request方法是GET ,请求不会被取消并且响应类型是JSON。

  5. Next, we’ll complete the request by calling flush on the request and pass our mock data.

    接下来,我们将通过对请求调用flush来完成请求并传递我们的模拟数据。

Note: While using beforeEach for variables, note that the variable will be available for all the assertions in that describe block and the describe blocks inside as well. For changing the value of mock data, you can create another describe block.

注意 :在对变量使用beforeEach时,请注意,该变量将可用于该describe块中的所有断言以及内部的describe块。 要更改模拟数据的值,可以创建另一个describe块。

测试管 (Testing Pipes)

Writing test cases for the pipes is very easy in Angular. Let’s create a simple pipe, named file-name.pipe.ts, where you can get the file’s name from a file path.

在Angular中,为管道编写测试用例非常容易。 让我们创建一个名为file-name.pipe.ts的简单管道,您可以在其中从文件路径获取文件名。

import { Pipe, PipeTransform } from '@angular/core';@Pipe({
name: 'fileName'
})export class FileNamePipe implements PipeTransform { transform(value: string): any {
let file = value.split('/');
let index = file.length - 1;
return file[index];
}
}

We’ll now create the test cases for this pipe.

现在,我们将为此管道创建测试用例。

import { FileNamePipe } from './file-name.pipe';describe('FileNamePipe', () => {
let pipe: FileNamePipe; beforeEach(() => {
pipe = new FileNamePipe();
});it('should get file name from file path', () => {
expect(pipe.transform('https://path/to/your/file/file.docx')).toBe('file.docx');
});});

A few points to note here:

这里要注意几点:

  1. Before each test spec is run, we create a new instance of FileName pipe and store in the pipe variable.

    在运行每个测试规范之前,我们创建一个FileName管道的新实例并将其存储在pipe变量中。
  2. As the pipes have only one function mostly, i.e., transform(), we’ll test it by passing some input in it and expect an output.

    由于管道主要只有一个功能,即transform(),我们将通过在其中传递一些输入并期望输出来对其进行测试。

测试属性指令 (Testing Attribute Directives)

An Attribute directive changes the appearance or behavior of a DOM element. Let’s create a simple directive for this that changes the color of the text.

Attribute指令更改DOM元素的外观或行为。 为此,我们创建一个简单的指令来更改文本的颜色。

import { Directive, ElementRef, Input, OnChanges } from '@angular/core';@Directive({
selector: '[changeColor]'
})export class ChangeColorDirective implements OnChanges {
color = 'rgb(0, 0, 255)';
@Input('changeColor') changedColor;constructor(private el: ElementRef) {
el.nativeElement.style.customProperty = true;
}ngOnChanges() {
this.el.nativeElement.style.color = this.changedColor || this.color;
}
}

We can use this directive in our component like below:

我们可以在组件中使用此指令,如下所示:

<h1 changeColor>Default Color</h1>
<h2 changeColor="blue">Color Changed</h2>

Now, let’s first set up our change-color.directive.spec.ts file and resolve the dependencies.

现在,让我们首先设置我们的change-color.directive.spec.ts文件并解决依赖关系。

import { ChangeColorDirective } from './change-color.directive';
import { TestBed, ComponentFixture, async } from '@angular/core/testing';
import { Component, DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';describe('ChangeColorDirective', () => { let fixture: ComponentFixture<MockComponent>;
let directive: DebugElement[];@Component({
template: `<h1 changeColor>Default Color</h1>
<h2>No Color Change</h2>
<h3 changeColor="red">Color Changed</h3>`
})class MockComponent { }beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ MockComponent, ChangeColorDirective ]
})
fixture = TestBed.createComponent(MockComponent);
directive = fixture.debugElement.queryAll(By.directive(ChangeColorDirective));
fixture.autoDetectChanges();
})
})

Key points to note here:

这里要注意的要点:

  1. Create MockComponent where we’ll add the HTML template using our directive and write the test cases around it.

    创建MockComponent ,在其中我们将使用指令添加HTML模板,并围绕它编写测试用例。

  2. We are fetching all the instances from our HTML template where the directive has been used by using By.directive.

    我们正在使用By.directive从HTML模板中获取使用了指令的所有实例。

  3. In case you are using debugElement.query instead of queryAll, make sure to change the directive type to DebugElement from DebugElement[].

    如果您使用的是debugElement.query而不是queryAll,请确保将指令类型从DebugElement []更改为DebugElement

Now, let’s write some test cases for our directive

现在,让我们为指令编写一些测试用例

it('should have 2 elements with changed color directive', async(() => {
expect(directive.length).toEqual(2);
}));it('should change 1st element to default color', async(() => {
const dir = directive[0].injector.get(ChangeColorDirective);
const h1Color = directive[0].nativeElement.style.color;
expect(h1Color).toBe(dir.color);
}));it('should not change color of 2nd element', async(() => {
const h2Color = fixture.debugElement.query(By.css('h2'));
expect(h2Color.properties.customProperty).toBeUndefined();
}));it('should change 3rd element to defined color', async(() => {
const h3Color = directive[1].nativeElement.style.color;
expect(h3Color).toBe('red');
}));
  1. Now, here in the first test case, we are checking the number of instances where the directive is being used. In our MockComponent, we have two instances where we’ve added the changeColor directive.

    现在,在第一个测试用例中,我们正在检查使用指令的实例数。 在我们的MockComponent中,我们有两个实例,其中添加了changeColor指令。
  2. Next, we’ll inject the directive instance and get the default color. Since we are not defining any color in the changeColor attribute of <h1> tag, we’ll expect that the h1 has the default color.

    接下来,我们将注入指令实例并获得默认颜色。 由于我们没有在<h1>标签的changeColor属性中定义任何颜色,因此我们希望h1具有默认颜色。

  3. In the next test case, we’ll expect that custom property is undefined since we don’t have changeColor attribute for <h2> tag.

    在下一个测试案例中,由于我们没有<h2>标签的changeColor属性,因此我们希望自定义属性未定义

  4. At last, we’ll expect the color of the text in <h3> tag is the same as the color defined in the attribute, i.e, red.

    最后,我们希望<h3>标记中的文本颜色与属性中定义的颜色相同,即红色。

  1. https://angular.io/guide/testing

    https://angular.io/guide/testing

  2. https://angular.io/guide/testing-services

    https://angular.io/guide/testing-services

Stay tuned for Part 3 of Unit testing in Angular where we’ll explore how to test components and services with dependencies on other components/services.

请继续关注 Angular单元测试的 第3部分 ,我们将探索如何测试依赖于其他组件/服务的组件和服务。

翻译自: https://medium.com/khojchakra/developers-guide-to-unit-testing-in-angular-part-2-services-pipes-directives-f1045495f98e

angular指令和管道

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值