尝试 运行 Angular HttpClient Jasmine 测试实时 REST API:没有任何反应
Trying to run Angular HttpClient Jasmine test against live REST API: nothing happens
我有一个用 .Net Core 编写的简单 "Contacts" REST 服务。它工作正常。
我正在尝试编写一个 Angular 8.3 客户端与之通信。
我做的前两件事是:
- 创建Contact.ts和Note.ts(对应REST模型)
- 创建一个 Angular 服务来与 .Net Core REST API.
通信
我 认为 也许测试服务的最佳方法是使用自动生成的单元测试,contacts.service.spec.ts
。我 不想 想使用模拟服务:我想使用 "live" HttpClient 所以我的 Angular "contacts" 服务可以直接与 .网络核心 API.
它不工作:没有错误,没有警告:测试 "passes" 甚至没有尝试发送 HTTP 消息或等待 HTTP 响应。
问:如何根据实时 REST 服务调试我的 Angular 服务?
问:我可以使用 contacts.service.spec.ts
Jasmine test/Karma runner,还是应该 "something else" 单步执行代码?
提前致谢!
models/contact.ts:
export class Contact {
ContactId?: number;
Name: string;
EMail: string;
Phone1: string;
Phone2: string;
Address1: string;
Address2: string;
City: string;
State: string;
Zip: string;
}
models/note.ts
export class Note {
NoteId?: number;
Text: string;
Date: Date;
ContactId?: number;
}
services/contacts.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { Contact } from '../models/Contact';
import { Note } from '../models/Note';
@Injectable({
providedIn: 'root'
})
export class ContactsService {
myAppUrl: string;
myApiUrl: string;
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json; charset=utf-8'
})
};
constructor(private http: HttpClient) {
this.myAppUrl = 'http://localhost:53561/'; // environment.appUrl;
this.myApiUrl = 'api/Contacts/';
}
getContacts(): Observable<Contact[]> {
const url = this.myAppUrl + this.myApiUrl;
return this.http.get<Contact[]>(url)
.pipe(
retry(1)
);
}
}
services/contacts.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { ContactsService } from './contacts.service';
describe('ContactsService', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ContactsService]
}));
it('should be created', () => {
const service: ContactsService = TestBed.get(ContactsService);
expect(service).toBeTruthy();
});
it('should retrieve all contacts', () => {
const contactsService: ContactsService = TestBed.get(ContactsService);
let observable = contactsService.getContacts();
expect(observable).toBeTruthy();
debugger;
observable.subscribe(data => {
debugger;
console.log("Done");
},
error => {
debugger;
console.error("observable error");
});
});
});
ng测试
我已经尝试将 done() 添加到我的服务测试中,并尝试在单元测试中实例化 HttpClient。它仍然没有对 REST 服务器进行任何 HTTP 调用:(
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { HttpClient } from '@angular/common/http';
import { ContactsService } from './contacts.service';
describe('ContactsService', () => {
let httpClient: HttpClient;
let service: ContactsService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ContactsService, HttpClient]
});
// ERROR:
// "Timeout - Async callback was not invoked within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
// Tried changing to 20000 - still getting Timeout...
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; // Getting timeout @default 5000
httpClient = TestBed.get(HttpClient);
//service = TestBed.get(ContactsService);
service = new ContactsService(httpClient);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should retrieve all contacts', (done: DoneFn) => {
service.getContacts().subscribe(data => {
done();
});
});
});
当前错误(尽管在测试中手动更新超时值)
Error: Timeout - Async callback was not invoked within 20000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
Error: Timeout - Async callback was not invoked within 20000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
at <Jasmine>
感谢 Pytth 和 wessam yaacob。这是我的工作方式:
在 .Net Core REST 服务上配置 CORS
public class Startup
...
public void ConfigureServices(IServiceCollection services)
...
services.AddCors(options => {
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
...
app.UseCors("CorsPolicy");
我已经在做事了 - 但在这里注明很有用
使用 HttpClientModule 和 HttpClient 代替 HttpClientTestingModule 和 HttpTestingController
我从不想要使用"HttpClientTestingModule",因为我想与实时服务交谈 - 而不是进行模拟呼叫。
一路上我对代码进行了大量更改,但这是我最终完成的单元测试:
import { TestBed } from '@angular/core/testing';
import { HttpClientModule, HttpClient, HttpErrorResponse } from '@angular/common/http';
import { BlogPostService } from './blog-post.service';
describe('BlogPostService', () => {
let httpClient: HttpClient;
let service: BlogPostService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
});
httpClient = TestBed.get(HttpClient);
service = TestBed.get(BlogPostService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should retrieve blog posts', (done: DoneFn) => {
service.getBlogPosts().subscribe(data => {
done();
});
});
});
最后注:
CORS NOT 似乎可以工作 UNLESS 我使用了 HTTPS:
export class BlogPostService {
...
constructor(private http: HttpClient) {
this.myAppUrl = 'https://localhost:44330/' // CORS error if 'http://localhost:44330/'
this.myApiUrl = 'api/BlogPosts/';
...
PS:"unit tests"和"integration tests"之间的"academic distinction"我都知道了。我只是希望 Angular "unit test" 框架能给我在 Java 世界中使用 static void main (String[] args)
代码时同样的便利。
事实证明不是这种情况...
我还没有尝试过针对这种情况的 e2e 测试 - 创建一个虚拟页面(一个简单的组件)并将其用于测试会更容易...
您需要使用茉莉花提供的done
。将编辑更新:
https://codecraft.tv/courses/angular/unit-testing/asynchronous/#_jasmines_code_done_code_function
关于你的更新:这应该会让你朝着正确的方向前进
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { HttpClient, HttpHeaders } from '@angular/common/http';
describe('LoginRepository', () => {
let httpClient: HttpClient;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
});
service = TestBed.get(LoginRepository);
httpClient = TestBed.get(HttpClient);
});
describe('#login', () => {
it('makes http request', () => {
spyOn(httpClient, 'post');
//...
如果你要根据你的真实休息来测试你的服务 api 所以你必须用 HttpClientModule
替换 HttpClientTestingModule
HttpClientTestingModule
仅用于模拟
aslo 在您的设置文件中,您必须在接受的源中添加测试域 url 以避免 ->> CORS 策略:否 'Access-Control-Allow-Origin'
in your case http://localhost:9876
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
......
app.UseCors(options =>
options.WithOrigins("http://localhost:9876")
......
}
我有一个用 .Net Core 编写的简单 "Contacts" REST 服务。它工作正常。
我正在尝试编写一个 Angular 8.3 客户端与之通信。
我做的前两件事是:
- 创建Contact.ts和Note.ts(对应REST模型)
- 创建一个 Angular 服务来与 .Net Core REST API. 通信
我 认为 也许测试服务的最佳方法是使用自动生成的单元测试,contacts.service.spec.ts
。我 不想 想使用模拟服务:我想使用 "live" HttpClient 所以我的 Angular "contacts" 服务可以直接与 .网络核心 API.
它不工作:没有错误,没有警告:测试 "passes" 甚至没有尝试发送 HTTP 消息或等待 HTTP 响应。
问:如何根据实时 REST 服务调试我的 Angular 服务?
问:我可以使用 contacts.service.spec.ts
Jasmine test/Karma runner,还是应该 "something else" 单步执行代码?
提前致谢!
models/contact.ts:
export class Contact {
ContactId?: number;
Name: string;
EMail: string;
Phone1: string;
Phone2: string;
Address1: string;
Address2: string;
City: string;
State: string;
Zip: string;
}
models/note.ts
export class Note {
NoteId?: number;
Text: string;
Date: Date;
ContactId?: number;
}
services/contacts.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { Contact } from '../models/Contact';
import { Note } from '../models/Note';
@Injectable({
providedIn: 'root'
})
export class ContactsService {
myAppUrl: string;
myApiUrl: string;
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json; charset=utf-8'
})
};
constructor(private http: HttpClient) {
this.myAppUrl = 'http://localhost:53561/'; // environment.appUrl;
this.myApiUrl = 'api/Contacts/';
}
getContacts(): Observable<Contact[]> {
const url = this.myAppUrl + this.myApiUrl;
return this.http.get<Contact[]>(url)
.pipe(
retry(1)
);
}
}
services/contacts.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { ContactsService } from './contacts.service';
describe('ContactsService', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ContactsService]
}));
it('should be created', () => {
const service: ContactsService = TestBed.get(ContactsService);
expect(service).toBeTruthy();
});
it('should retrieve all contacts', () => {
const contactsService: ContactsService = TestBed.get(ContactsService);
let observable = contactsService.getContacts();
expect(observable).toBeTruthy();
debugger;
observable.subscribe(data => {
debugger;
console.log("Done");
},
error => {
debugger;
console.error("observable error");
});
});
});
ng测试
我已经尝试将 done() 添加到我的服务测试中,并尝试在单元测试中实例化 HttpClient。它仍然没有对 REST 服务器进行任何 HTTP 调用:(
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { HttpClient } from '@angular/common/http';
import { ContactsService } from './contacts.service';
describe('ContactsService', () => {
let httpClient: HttpClient;
let service: ContactsService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ContactsService, HttpClient]
});
// ERROR:
// "Timeout - Async callback was not invoked within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
// Tried changing to 20000 - still getting Timeout...
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; // Getting timeout @default 5000
httpClient = TestBed.get(HttpClient);
//service = TestBed.get(ContactsService);
service = new ContactsService(httpClient);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should retrieve all contacts', (done: DoneFn) => {
service.getContacts().subscribe(data => {
done();
});
});
});
当前错误(尽管在测试中手动更新超时值)
Error: Timeout - Async callback was not invoked within 20000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
Error: Timeout - Async callback was not invoked within 20000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
at <Jasmine>
感谢 Pytth 和 wessam yaacob。这是我的工作方式:
在 .Net Core REST 服务上配置 CORS
public class Startup ... public void ConfigureServices(IServiceCollection services) ... services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); }); ... public void Configure(IApplicationBuilder app, IWebHostEnvironment env) ... app.UseCors("CorsPolicy");
我已经在做事了 - 但在这里注明很有用
使用 HttpClientModule 和 HttpClient 代替 HttpClientTestingModule 和 HttpTestingController
我从不想要使用"HttpClientTestingModule",因为我想与实时服务交谈 - 而不是进行模拟呼叫。
一路上我对代码进行了大量更改,但这是我最终完成的单元测试:
import { TestBed } from '@angular/core/testing'; import { HttpClientModule, HttpClient, HttpErrorResponse } from '@angular/common/http'; import { BlogPostService } from './blog-post.service'; describe('BlogPostService', () => { let httpClient: HttpClient; let service: BlogPostService; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientModule], }); httpClient = TestBed.get(HttpClient); service = TestBed.get(BlogPostService); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should retrieve blog posts', (done: DoneFn) => { service.getBlogPosts().subscribe(data => { done(); }); }); });
最后注:
CORS NOT 似乎可以工作 UNLESS 我使用了 HTTPS:
export class BlogPostService { ... constructor(private http: HttpClient) { this.myAppUrl = 'https://localhost:44330/' // CORS error if 'http://localhost:44330/' this.myApiUrl = 'api/BlogPosts/'; ...
PS:"unit tests"和"integration tests"之间的"academic distinction"我都知道了。我只是希望 Angular "unit test" 框架能给我在 Java 世界中使用 static void main (String[] args)
代码时同样的便利。
事实证明不是这种情况...
我还没有尝试过针对这种情况的 e2e 测试 - 创建一个虚拟页面(一个简单的组件)并将其用于测试会更容易...
您需要使用茉莉花提供的done
。将编辑更新:
https://codecraft.tv/courses/angular/unit-testing/asynchronous/#_jasmines_code_done_code_function
关于你的更新:这应该会让你朝着正确的方向前进
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { HttpClient, HttpHeaders } from '@angular/common/http';
describe('LoginRepository', () => {
let httpClient: HttpClient;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
});
service = TestBed.get(LoginRepository);
httpClient = TestBed.get(HttpClient);
});
describe('#login', () => {
it('makes http request', () => {
spyOn(httpClient, 'post');
//...
如果你要根据你的真实休息来测试你的服务 api 所以你必须用 HttpClientModule
HttpClientTestingModule
HttpClientTestingModule
仅用于模拟
aslo 在您的设置文件中,您必须在接受的源中添加测试域 url 以避免 ->> CORS 策略:否 'Access-Control-Allow-Origin'
in your case http://localhost:9876
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
......
app.UseCors(options =>
options.WithOrigins("http://localhost:9876")
......
}