Angular 7 组件测试使用原始服务而不是模拟服务

2024-04-12

我正在尝试测试具有注入服务的组件。我想在我的测试中提供模拟服务。然而,测试使用原始服务而不是模拟服务(我知道这一点是因为我收到“没有 HttpClient 的提供程序!”错误,而且我在测试中输出的原始服务中有一个 console.log)。

我可以通过导入 HttpClientTestingModule 来修复错误,但这并不能解决使用原始服务而不是模拟服务这一事实。

有什么想法我做错了吗?

这是我的测试代码。角度版本 7

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { HelloWorldComponent } from '../../app/components/hello-world/hello-world.component';
import { HelloWorldService } from '../../app/services/hello-world.service';

describe('HelloWorldComponent', () => {

  let component: HelloWorldComponent;
  let fixture: ComponentFixture<HelloWorldComponent>;
  let mockHelloWorldService;
  
  beforeEach(() => {

    mockHelloWorldService = jasmine.createSpyObj(['getHelloWorld']);
    
    TestBed.configureTestingModule({
      imports: [],
      declarations: [HelloWorldComponent],
      providers: [
        [{ provide: HelloWorldService, useClass: mockHelloWorldService }]
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(HelloWorldComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
	
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
  
});

UPDATE

我已经尝试过 overrideProvider,现在我收到了“无法读取未定义的属性‘订阅’”错误,这感觉像是进步......

这是我的测试代码

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { HelloWorldComponent } from '../../app/components/hello-world/hello-world.component';
import { HelloWorldService } from '../../app/services/hello-world.service';
import { of } from 'rxjs';

describe('HelloWorldComponent', () => {

  let component: HelloWorldComponent;
  let fixture: ComponentFixture<HelloWorldComponent>;
  let mockHelloWorldService;

  beforeEach(async(() => {
    mockHelloWorldService = jasmine.createSpyObj(['getHelloWorld']);
    TestBed.configureTestingModule({
      imports: [],
      declarations: [HelloWorldComponent]
    });
    TestBed.overrideProvider(HelloWorldService, { useValue: mockHelloWorldService });
    TestBed.compileComponents();

  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HelloWorldComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

这是我的组件

import { Component, OnInit } from '@angular/core';
import { HelloWorldService } from '../../services/hello-world.service';

@Component({
  selector: 'app-hello-world',
  templateUrl: './hello-world.component.html',
  providers: [HelloWorldService]
})
export class HelloWorldComponent implements OnInit {

  helloWorldMessage: any;
  constructor(private helloWorldService: HelloWorldService) { }

  ngOnInit() {
    this.getHelloWorldMsg();
  }

  getHelloWorldMsg() {
    this.helloWorldService
      .getHelloWorld()
      .subscribe((data) => {
        this.helloWorldMessage = data;
        }, err => this.handleErrorResponse('There was a problem loading the hello world message', err));
  }

  handleErrorResponse(errorMsg: string, error?: any) {
    console.log("There was a problem getting the message");
  }
}

这是我的服务

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { environment } from '../../environments/environment';

@Injectable()
export class HelloWorldService {
  constructor(private http: HttpClient) { }

  getHelloWorld(): Observable<any> {
    console.log("Why is the test coming here when I provide a mock?");
    var getHelloWorldApiUrl = environment.apiUrl + "/api/v1.0/helloworld/GetHelloWorldMessageAuth";
    return this.http
    .get(getHelloWorldApiUrl);
  }
}

我在上面的代码中看到两个问题:

  • 您的 TestBed 的提供者数组中有一组额外的方括号。我认为这不是一个主要问题,它只是语义上不正确。
  • 当您提供HelloWorldService在提供者数组中,您已指定useClass,但提供了一个对象(这就是jasmine.createSpyObj()产生),所以你应该指定useValue.

我希望这有帮助。

Update:

好吧,你已经走了很长的路了!您纠正了我上面概述的两个问题,并完成了overrideProvider()之前compileComponents()正如我在对另一个答案的评论中建议的那样beforeEach()里面一个async().

我要求查看所有其他代码的原因是这样我可以快速将其放在下面堆栈闪电战 https://stackblitz.com/edit/stackoverflow-q-54036099?file=app%2Fhello-world.component.spec.ts供测试用。正如您在 StackBlitz 中看到的,测试现已通过。

我只在其中添加了一行beforeEach()声明来自您的间谍的 returnValue,以便您的组件中的订阅有一个可订阅的 Observable:

mockHelloWorldService.getHelloWorld.and.returnValue(of('Test Message'));

我在调用之前添加了这个fixture.detectChanges()因为这会调用ngOnInit(),并且间谍程序需要在执行之前设置返回值ngOnInit()这样它就会正确执行并且不会给您所看到的错误。

我还在规范中添加了一行,以展示如何测试 Observable 的结果是否正确设置为组件变量:

expect(component.helloWorldMessage).toEqual('Test Message');

请注意,通过在组件声明的providers数组中指定HelloWorldService,您的测试会显着复杂化。如果您将此服务作为根中的单例提供,这将大大简化事情,包括您的测试方式。详情请参阅官方文档 https://angular.io/guide/singleton-services.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular 7 组件测试使用原始服务而不是模拟服务 的相关文章

随机推荐

  • 如何旋转 SCNBox

    我正在尝试旋转SCNBox我创建使用swipe gestures 例如 当我向右滑动时 该框应旋转 90 度Y axis当我向左滑动时为 90degs 为了实现这一点 我一直在使用节点的SCNAction rotateByX方法来执行旋转动
  • Java中如何预加载类? [复制]

    这个问题在这里已经有答案了 在我的 Swing 界面中首次打开新的 JInternalFrame 需要一些时间 根据探查器 大部分时间都花在 Classloader loadClass 方法上 据我所知 它会在需要时动态加载类 并且实际上
  • 如何创建播放列表

    我正在尝试创建一个仅提供编辑文本和图像按钮的应用程序 如果单击按钮 则会将专辑添加到播放列表中 并在编辑文本框中命名 专辑应随机选择 不用说 专辑曲目应该按正确的顺序排列 我可以稍后添加更多功能 例如 保存 覆盖 删除等 我有界面 但正在努
  • Magento 1.9 注册后重定向客户

    我想在 Magento 1 9 中成功注册后将所有客户重定向到自定义页面 我已经尝试了很多事情 首先 我成功地覆盖了核心客户帐户控制器 我尝试自定义以下操作 创建后动作 successProcessRegistration welcome客
  • 在 C# 中实现动态 Web Scraper 的逻辑

    我希望在 C 窗口窗体中开发一个 Web scraper 我想要完成的任务如下 从用户处获取 URL 在WINForms中的IE UI控件 嵌入式浏览器 中加载网页 允许用户选择文本 连续 小 不超过 50 个字符 从加载的网页 当用户希望
  • 第三个克隆海龟

    我在尝试制作追逐游戏时制作了这个程序 但我偶然发现了一些非常奇怪的东西 我创建了海龟的克隆体 但在地图中间出现了第三个 有谁知道是什么原因造成的 import turtle sc turtle Screen t turtle Turtle
  • Java加密AES,PHP解密AES

    我正在寻找一种在 Java 中加密字符串并在 PHP 中解密的方法 我发现this http www logikdev com 2010 11 01 encrypt with php decrypt with java 在 Stackove
  • 阻止 Google Analytics 在开发环境、ASP.NET MVC 中收集数据

    我有一个 ASP NET MVC 3 应用程序 并且我已经设置了 Google 分析 问题是 每次我从 Visual Studio 运行时 Google 脚本都会开始收集数据 这当然会扭曲实际结果 阻止 Google Analytics 收
  • 本机客户端上用于 SMTP 的 Office 365 XOAUTH2 535 5.7.3 身份验证失败

    我尝试通过office 365的smtp发送邮件 我在azure中为本机客户端设置了应用程序注册并设置了权限SMTP Send 但是当我连接时 我已经能够获得令牌 但发送不起作用 在我阅读的所有其他文章中 我需要设置 https outlo
  • 无法创建类型的常量值在此上下文中仅支持基本类型或枚举类型

    我在下面的查询中收到此错误 无法创建类型的常量值API Models PersonProtocol 此上下文中仅支持基本类型或枚举类型 ppCombined下面是一个IEnumerable的对象PersonProtocolType 由 2
  • Firebase 身份验证 - 开源 Android 应用

    有没有办法Firebase 身份验证 https firebase google com docs auth gclid EAIaIQobChMIhKuIo zV4wIVhRx9Ch1VwAh7EAAYASAAEgLRrvD BwE在开源应
  • SQLAlchemy 查询 API 在提示下无法正常工作

    我正在尝试使用查询 API 创建带有 MAX EXECUTION TIME 30000 提示的 MySQL 查询 我的代码大致是 from flask sqlalchemy import SQLAlchemy class MyTable S
  • 为什么我可以转换为 NSManagedObject 但不能转换为我的实体的类型?

    我在一个新项目中使用 Core Data 的 Swift 样板代码 我的 xcdatamodeld文件定义了一个实体 Task 具有单个属性 name 我有一个Task swift文件看起来像这样 import CoreData class
  • 用于 RHEL 的 gdb-multiarch

    我正在尝试寻找方法来运行gdb 多架构RHEL 中的命令 我已经安装了用于 ARM 处理的 QEMU 模拟器 我想安装GDB进行调试 我能够安装GDB 多体系结构在 Ubuntu 中运行命令成功 sudo apt get GDB multi
  • CSS:如何使盒子内部的角变圆? [复制]

    这个问题在这里已经有答案了 有border radius属性为圆形框角 但是如何在块内圆角 例如减去圆 像这儿 http malsup com jquery corner http malsup com jquery corner 卷曲设置
  • preg_match_all() 在不同的服务器上表现不同

    下面的代码在我的 PC 上的 XAMPP 上运行完美 但在我新购买的 VPS 上不起作用 它使我的代码崩溃了 preg match all regex siU string matches PREG SET ORDER 这预计只是从 HTM
  • 如何从 Android 中的自定义 CameraView 捕获图像?

    我需要捕捉图像 from 所需部分 of the screen 捕捉图像 from camera 当时其他屏幕内容保持原样 这怎么样possible 尝试使用表面视图 for 创造动态 camera查看并设置您需要的部分 下面的代码尝试 变
  • 从 pthread 调用 sleep() 是否会使线程或进程进入睡眠状态?

    我看到有一个关于linux pthread睡眠 https stackoverflow com questions 3633089 pthread sleep linux 然而 当我在 Linux 机器上查找手册页时 我看到以下内容 概要
  • 在 Mac OS X 的 Swing 应用程序中嵌入 JRE

    我必须发布带有嵌入式 JRE 的 swing 应用程序 包含应用程序 JRE bat sh 的压缩存档可以在 Windows 和 Linux 上实现 用户下载 zip 文件 解压缩并启动应用程序 完美的 但现在 我必须为 Mac OS X
  • Angular 7 组件测试使用原始服务而不是模拟服务

    我正在尝试测试具有注入服务的组件 我想在我的测试中提供模拟服务 然而 测试使用原始服务而不是模拟服务 我知道这一点是因为我收到 没有 HttpClient 的提供程序 错误 而且我在测试中输出的原始服务中有一个 console log 我可