angular - 尝试针对实时 REST API : nothing happens 运行 Angular HttpClient Jasmine 测试

标签 angular jasmine angular-httpclient

我有一个用 .Net Core 编写的简单“联系人”REST 服务。它工作正常。

我正在尝试编写一个 Angular 8.3 客户端来与之交谈。

我做的前两件事是:

  • 创建 Contact.ts 和 Note.ts(对应于 REST 模型)
  • 创建 Angular 服务以与 .Net Core REST API 通信。

  • 我认为测试服务的最佳方法可能是使用自动生成的单元测试,contacts.service.spec.ts .我不想使用模拟服务:我想使用“实时”HttpClient,这样我的 Angular“联系人”服务就可以直接与 .Net Core API 对话。

    它不起作用:没有错误,没有警告:测试只是“通过”,甚至没有尝试发送 HTTP 消息或等待 HTTP 响应。

    问:如何针对实时 REST 服务调试我的 Angular 服务?

    问:我可以使用contacts.service.spec.ts吗? Jasmine 测试/Karma runner,还是我应该做“其他事情”来逐步执行代码?

    先感谢您!

    模型/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; 
    }
    

    模型/note.ts
    export class Note {
      NoteId?: number;
      Text: string;
      Date: Date;
      ContactId?: number;
    }
    

    服务/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)
        );
      }
    }
    

    服务/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 测试

    ng test

    我试过添加 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();
        });
      });
    });
    
  • 最后说明:

    除非我使用 HTTPS,否则 CORS 似乎不起作用:
    export class BlogPostService {
      ...
      constructor(private http: HttpClient) {
          this.myAppUrl = 'https://localhost:44330/'  // CORS error if 'http://localhost:44330/'
          this.myApiUrl = 'api/BlogPosts/';
          ...
    

  • PS:我知道“单元测试”和“集成测试”之间的“学术区别”。我只是希望 Angular“单元测试”框架能给我带来与使用 static void main (String[] args) 相同的便利Java 世界中的代码。

    事实证明,情况绝对不是这样......

    我还没有尝试过针对这种情况的 e2e 测试 - 只需创建一个虚拟页面(一个简单的组件)并将其用于测试会更容易......

    最佳答案

    如果您要根据真实的休息 api 测试您的服务,则必须替换 HttpClientTestingModuleHttpClientModuleHttpClientTestingModule仅用于 mock

    同样在您的设置文件中,您必须在接受的源中添加测试域 url 以避免 ->> CORS 策略:没有“访问控制允许源”

    in your case http://localhost:9876


       public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            { 
                  ......
                  app.UseCors(options =>
                  options.WithOrigins("http://localhost:9876") 
                  ......
            }
    

    关于angular - 尝试针对实时 REST API : nothing happens 运行 Angular HttpClient Jasmine 测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59204306/

    相关文章:

    css - Material Spinner 垂直对齐

    angular - 如何导入模块或有条件地提供服务? (AOT)

    angular - 如果该组件已经存在一个类,则 routerLinkActive 类不适用

    javascript - Jasmine spy 不工作

    javascript - Jasmine:如何通过测试套件函数来描述方法?

    javascript - 测试 'isChecked' 属性是否已更改

    angular - 使用或不使用订阅将数据发布到 API

    javascript - Angular:刷新浏览器页面后无法重新加载数据

    Angular 7 : Post request always send a null body

    angular - 从 Ionic 2 更新到 Ionic 3,现在由于 "Unexpected token {"错误而无法构建