Angular入门:简述单元测试排错

这篇具有很好参考价值的文章主要介绍了Angular入门:简述单元测试排错。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

零、前言

学习Angular的时候,总感觉特别的复杂、高级,以至于产生畏惧心理,这种心理尤其体现在单元测试上。

今天被醍醐灌顶之后,感觉单元测试的报错信息也不是那么难看懂了。

(文章的后半段是记录我自己的一次单元测试的过程,为了不耽误读者时间,我把结论写在第一小节。)

一、分析报错信息

启动单元测试后,映入眼帘的是一堆信息:

先来看顶部的信息:

最上面的一排点···············是整个项目的测试总数,下面的Ran 1 of 58 specs是一共58个测试,本次测试启动了一个。

下面的1 spec, 1 failure是本次启动的一个测试中,有一个出错了,然后列出了所有报错的测试项,以及错误信息。

然后看错误信息:

顶上的 TypeError: Cannot set property ‘workId’ of undefined 是主要的错误类型。

本文举例的错误是类型错误,不能对一个 undefined 对象调用 workId 属性。

下面的那一大片代码,是方法的堆栈
举个例子:如果 A( )调用了 B( ), B( ) 调用了C( ),那么堆栈情况就是这样:

我们知道,栈是先进后出,队列是先进先出,这里使用的就是栈。

  • 当A( )方法被调用时,内存加载A( ),此时A就在栈上
  • 执行的时候突然发现,A( )需要调用B( )方法,此时应该加载B( )
  • 但A( )还没有执行完毕,不能释放,所以就用栈的方式,把A( )压在下面并且冻结
  • B( )的执行过程中又需要C( ),所以B冻结,C入栈。
  • 等到C( )执行完之后,把结果返回给B( ),此时C( )被释放,出栈
  • B( )被解冻,拿到C( )的返回值,继续执行后面的语句
  • 后面的过程同理……

所以,这张图的意思,就是堆栈,最上面的方法,是当前的活跃方法,也就是出错的方法:

可以清晰的看到at WorkStubService.getById (http://localhost:9877/_karma_webpack_/src/app/service/service-tesing/work-stub.service.ts:76:32)

翻译一下就是,错误发生在WorkStubService类的getById方法,链接的最后显示了,是work-stub.service.ts文件的第76行的第32个字符,出现了问题。

然后定位到这行代码,就可以清楚的找到问题了。

分析报错信息的方法介绍,到此结束。

二、记一次排错实录

计划测试EditComponent组件的C层初始化。

C层:

export class EditComponent implements OnInit {

  work = new Work();
  params = {
    workId: 0
  };
  constructor(private workService: WorkService) {
  }

  ngOnInit() {
    this.params.workId = 0;
    this.load();
  }


  public load() {
    this.workService.getById({id: this.params.workId})
      .subscribe((data) => {
        this.work = data;
        console.log(this.work);
      }, () => {
        console.log('error');
      });
  }
  
}

ngOninit调用load方法,load调用service来获取数据,

所以测试的思路就是让组件初始化,然后断言C层向M层的传值,以及断言M层的返回值即可。

describe('Page -> Teacher -> EditComponent', () => {
  let component: EditComponent;
  let fixture: ComponentFixture<EditComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ EditComponent ],
      imports: [
        HttpClientTestingModule,
      ],
      providers: [
        {provide: WorkService, useClass: WorkStubService}
      ]
    })
      .compileComponents();
  }));

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

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


  it('组件初始化发起请求测试', () => {
    /* 获取请求参数 */
    const workService: WorkStubService = TestBed.get(WorkService);
    const queryParam = workService.pageParamsCache;

    /* 断言传入的参数值与组件中的参数值相同 */
    expect(queryParam.workId).toEqual(component.params.workId);
  });


  it('组件初始化V层渲染', () => {
    /* 断言总行数及第一行的内容绑定符合预期 */

    expect(component.work.id).toBe(1);
    expect(component.work.content).toBe('<p>content</p>');
    expect(component.work.item).toBe(new Item({name: 'Item'}));
    expect(component.work.score).toBe(100);
    expect(component.work.student).toBe(new Student({name: 'Student'}));
    expect(component.work.reviewed).toBe(true);

  });
});

一共三个小的测试项。为了模拟返回值,还需要一个假的M层。

export class WorkStubService {

  constructor() {
  }

  /* 传入参数缓存 */
  pageParamsCache: { page: number, size: number ,workId: number};

  /**
   * getById模拟方法
   * @param params 查询参数
   */
  getById(params: { id: number }): Observable<Work> {
    this.pageParamsCache.workId = params.id;
    const mockResult = new Work(
      {
            id: 1, content: '<p>content</p>', item: new Item({name: 'Item'}),
            score: 100, student: new Student({name: 'Student'}), reviewed: true});
    return of(mockResult);
  }
}

然后一运行测试,我懵了,所有模拟的返回值,全都是undefined:

带着疑惑的心态,开始看自己的代码,感觉哪里都没问题…
更何况这些代码是从老项目里面粘过来的,“不可能”出错。

为了找出不同,我把代码和老项目一行一行的对照,的确没有问题。

然后我发现了模拟M层的getById方法是灰色,还固执的认为可能是没有被调用:

我又打了一堆断点,事实证明,即使是灰色,也确实被执行了。

直到这时,我还没有仔细的看报错信息。

终于,无法自己解决了,只能问老师,然后才发现,关键在于报了一个TypeError: Cannot set property ‘workId’ of undefined

一看,undefined,于是又傻傻的去C层找定义变量的代码,


都有初始值,怎么会是undefined呢??

后来老师又提示了,看报错信息。才知道那一大堆信息,实际上是堆栈,如果要找到具体的出错位置,只需要看最上面的一行,就可以了。at WorkStubService.getById (http://localhost:9876/_karma_webpack_/src/app/service/service-tesing/work-stub.service.ts:76:32)

定位到代码,是模拟服务层的这一行出现了问题:

这个变量是这样定义的,换言之,只定义了类型,并没有初始化:

所以,在undefined对象上调用wordId,当然会出错了。我恍然大悟。

然后另一个疑惑产生了,我的代码是粘过来的,为什么在之前的项目里没报错呢?
仔细的看了老项目,才发现我的错误源自于一个细微的改动。

老项目是这么写的:

this.pageParamsCache = params;

把所有的参数直接赋值给pageParamsCache,不存在对它调用属性的问题。
而我为了方便,改成了:

this.pageParamsCache.workId = params.id;

这一改,就把原本的整体赋值,变成了赋值单个属性,但是pageParamsCache并没有初始化,所以才出现了undefined错误。

总结

无论初学什么技能,一定不要好高骛远,也不能自作主张,最重要的是遇到问题不要瞎猜,要按照合理的思维方式来思考。

青铜玩家冥思苦想半天都没有解决的问题,对于王者段位来说,就是两句话的事。这就是青铜和王者的差距。

为什么青铜玩家解决不了呢?因为我一开始的思考方向就错了。

作者:LYX6666

原文地址:https://segmentfault.com/a/1190000022175987文章来源地址https://www.toymoban.com/news/detail-826712.html

喜欢 0

到了这里,关于Angular入门:简述单元测试排错的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 探索Angular测试艺术:Angular Testing Recipes

    项目地址:https://gitcode.com/juristr/angular-testing-recipes Angular Testing Recipes是一个开源项目,由开发者Juri Strumpfloeger精心打造,旨在为Angular开发者提供一系列实用的测试策略和示例代码。该项目以GitCode为平台,以Markdown格式分享了关于单元测试、组件测试、服务测试等方面的实战技

    2024年04月22日
    浏览(34)
  • angular框架简介基础与使用(全文2w8字)前端框架angular

    本文的所有内容,可以在我的博客上看到,下面是地址。建议去博客看,因为csdn的这篇图片我没上传。 可以转载,但请注明出处 我的博客—点击跳转 https://numb.run Angular是谷歌开发的一款开源的web前端框架,诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀

    2024年02月02日
    浏览(42)
  • Angular:引领未来的前端框架

    Angular是一款由Google开发的强大前端框架,具有丰富的特性和卓越的性能。本文将介绍Angular的基本概念、特点、应用场景以及与其他框架的对比。 一、引言 随着Web应用程序的日益复杂,前端框架在开发过程中扮演着越来越重要的角色。Angular作为一款由Google主导的前端框架,

    2024年01月22日
    浏览(43)
  • 2023.07.07面试偏前端angular

    ==和===是JavaScript中的两个比较运算符,用于比较两个值的相等性。 ==是松散相等运算符,它会进行类型转换后再比较值是否相等。如果两个值的类型不同,==会尝试将它们转换为相同的类型,然后再进行比较。例如,1 == \\\'1\\\'会返回true,因为它们在进行比较之前会被转换为相同

    2024年02月13日
    浏览(40)
  • 前端Angular框架基础知识(一)

    1.1 数据绑定 数据驱动DOM:将组件 类 (.ts文件)中的数据显示在组件 模板 (.html文件)中,当类中的数据发生变化会自动同步到模板中. Angular中使用差值表达式进行数据绑定, {{ }}语法 1.2 属性绑定 1.2.1 普通属性 使用【属性名称】为元素绑定DOM对象属性 使用【attr.属性名称】为元

    2024年01月17日
    浏览(40)
  • 三大前端技术(React,Vue,Angular)

    React(也被称为React.js或ReactJS)是一个用于构建用户界面的JavaScript库。它由Facebook和一个由个人开发者和公司组成的社区来维护。 React可以作为开发单页或移动应用的基础。然而,React只关注向DOM渲染数据,因此创建React应用通常需要使用额外的库来进行状态管理和路由,Red

    2024年02月09日
    浏览(52)
  • angular测试API

    1. resetTestEnvironment 是 Angular 测试中的一个函数,用于重置测试环境。它通常与 initTestEnvironment 和 platformBrowserDynamicTesting 一起使用,以确保在多个测试套件之间正确清理和重置 Angular 测试环境。 这是 resetTestEnvironment 函数的形式: 在一些测试场景中,特别是在使用 Angular 测试工

    2024年02月09日
    浏览(28)
  • 关于 Angular 和 Node.js 版本的问题

    只有 Angular 12 才支持 Node.js 16 吗?Angular 10 呢? StackOverflow 有朋友抱怨关于 Angular 和 Node.js 版本的问题: 我的实际工作中,经常不得不启动旧的 Angular 项目,其中包含已弃用的 Angular 依赖项。 因为我经常运行最新的 Node.js 版本(至少是最新的 LTS 版本),所以我经常遇到无法

    2024年02月04日
    浏览(46)
  • angular快速入门教程

    安装: 1.安装node.js 2.安装angular 3.创建项目 4.文件结构: 5.运行 组件: 项目根模块:app.module.ts 定义的组件都需要在app.module.ts文件里先进行import引入 然后在@NgModule({deckartions:[]})声明 定义组件模板的两个方式: 1.使用templateurl引用一个html文件 2.使用template +es6的模板字符串

    2023年04月08日
    浏览(40)
  • Angular快速入门

    Angular 是一个由 Google维护的开源JavaScript框架,用于在HTML和JavaScript中构建Web应用程序,是三大框架之首。 不管是1还是2,Angular最显著的特征就是其 整合性 。涵盖了M、V、C/VM等各个层面,不需要组合、评估其它技术就能完成大部分前端开发任务。这样可以有效降低决策成本,

    2024年02月20日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包