【问题标题】:Unit testing of base class with jasmine and angular茉莉花和角基类的单元测试
【发布时间】:2020-07-22 14:08:48
【问题描述】:

我有一个在每个网格组件中使用的通用基类。

现在,我有网格组件的规范,但我想在单独的基本规范文件中添加基类的规范。

其背后的动机是删除重复代码并为基网格制作通用规范文件,该文件将为使用基类的每个网格提供服务。

我卡住了,我无法在基本规范文件中创建规范。基本上我想要一个函数下的基本文件中的所有规范,当这个函数从具有该组件的子类调用时,它应该返回该类的所有规范。

这是我目前拥有的以及我尝试过的。

组件层:

export class MyComponent extends BaseGrid<MyEntity> { 
    ... (and all other code like constructor and methods)... 
}

基础层:

export class BaseGrid<T> { 
    public async getData(): Promise<void> { ... }
}

... and 100 other functions

组件规格:

describe('MyComponent ', () => {
    let component: MyComponent;
    let fixture: ComponentFixture<MyComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [MyComponent],
            imports: [
                ...
        ],
            providers: [
            ],
        }).compileComponents().then(() => {
            fixture = TestBed.createComponent(MyComponent);
            component = fixture.componentInstance;
        });
    }));

    // here I created a reference function for my base class spec
    // Now, This is working but I don't want this **describe** and **it** to be here, 
    // it should be in the base file. so I can remove this repetitive code from all components.
    // And From here I just want to call one function let's say a **baseGridSpecs(component)**, 
    // that will load all the specs of base class in this component.
    describe('Should initialize Base grid', () => {
        it('should have proper component.', () => {
            const baseGridSpecs = new BaseGridSpecs<MyComponent>();
            baseGridSpecs.runBaseGridTests(component);
            baseGridSpecs.checkGetDataDefined(component);
        });
    });
});

基本规格:

export class BaseGridSpecs<T> {
  runBaseGridTests(component: any): void {
    expect(component).toBeTruthy();
  }

  checkGetDataDefined(component: any): void {
     expect(component.getData).toBeDefined();
  }
}

这个结构对我来说很好用,但它没有用,因为我的 describeit 仍在主要组件规范文件中。

我想要实现的只是调用基本规范函数,如baseGridSpecs.runBaseGridTests(component);,它应该为给定的通用组件呈现所有describeit 规范。

任何帮助将不胜感激...

【问题讨论】:

  • 如果所有子类都应该通过相同的测试套件来实际测试基类的逻辑,那么似乎可以只针对基类运行一次该套件,并且只留下特定于其套件中的子类测试.如果重点是确保所有子类共享某些行为,您可以编写规范,在其中列出子类并在每个子类的循环中运行规范。
  • @Shlang:是的,动机是所有子类都应该通过相同的测试套件来实际测试基类的逻辑,但我无法在基本规范文件中创建规范。基本上我想要一个函数下的基本文件中的所有规范,当这个函数从具有该组件的子类调用时,它应该返回该类的所有规范。

标签: angular typescript unit-testing jasmine karma-runner


【解决方案1】:

Jasmine 允许在 describe 块之外定义 it ,除非您从某个 describe 块中显式调用它们,否则这些定义将不会运行。 Official documentation 提出了两种使用这一事实的方法。

测试主题可以与上下文共享,但它需要您使用function 而不是箭头函数,并且可能很烦人且难以跟踪,尤其是当有许多嵌套块时,因此您对规范类的想法使感觉。

让我们考虑一个包含两个类的简化示例。 (Playground)

// Base.ts  
export class Base {
  baseMethod() {
    return 0;
  }
}

// Derived.ts
import { Base } from "./base";

export class Derived extends Base {
  derivedMethod() {
    return 1;
  }
}

检查基类部分的派生类的测试可以封装在BaseSpec中:

// base.spec.ts
export class BaseSpec {
  public component;

  checkComponentInitialized(): void {
    it("should have proper component", () => {
      expect(this.component).toBeTruthy();
    });
  }

  checkBaseMethodDefined(): void {
    it("should have baseMethod method", () => {
      expect(this.component.baseMethod).toBeDefined();
    });
  }

  itActsLikeABase(): void {
    this.checkComponentInitialized();
    this.checkBaseMethodDefined();
  }
}

这个类可以在其他地方使用

// derived.spec.ts
import { Derived } from "./derived";
import { BaseSpec } from "./base.spec";

describe("Derived", () => {
  describe("as a Base", () => {
    const baseSpec = new BaseSpec();

    beforeEach(() => {
      baseSpec.component = new Derived();
    });

    baseSpec.itActsLikeABase();
  });

  describe("as a Derived", () => {
    let component;
    beforeEach(() => {
      component = new Derived();
    });

    it("should have derivedMethod method", () => {
      expect(component.derivedMethod).toBeDefined();
    });
  });
});

免责声明

虽然这在技术上是可行的并且在某些情况下可能是合适的,但请在以这种方式编写测试之前三思而后行。继承是一个强大但经常被滥用的工具。由于测试共享行为而导致的重复很可能是意外重复,因为测试不应依赖于行为的实现方式。 Sharing behavior testing caveats

【讨论】:

  • 首先谢谢,我一定会试试这个,并会及时通知您。
  • Brilliant Shalang,它正在工作。谢谢。一旦我按照我想要的方式进行回答,我也会发布我的答案。
【解决方案2】:

所以在 Shalang 的帮助下,我能够在我的基本网格规范文件中添加单元测试。 这就是我所做的。

组件规格:

describe('MyComponent ', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async(() => {
      TestBed.configureTestingModule({
          declarations: [MyComponent],
          imports: [
              ...
      ],
          providers: [
          ],
      }).compileComponents().then(() => {
          fixture = TestBed.createComponent(MyComponent);
          component = fixture.componentInstance;
      });
  }));

  describe('Should initialize Base grid', () => {
    const baseGridSpecs = new BaseGridSpecs<ComponentModel>();

    beforeEach(() => {
      baseGridSpecs.component = component;
      baseGridSpecs.fixture = fixture;          
    });

    // Here for me dummyData is model's object with proper value, 
    // which I can use to check service based calls.
    baseGridSpecs.loadSpecs(dummyData);
  });
});

基本规格:

export class BaseGridSpecs<T> {
  public component;

  public fixture;

  loadSpecs(dummyData: any): void {
    describe('Should initialize base component with Proper methods', () => {
      it('should initialize properly.', () => {
        expect(this.component).toBeTruthy();
      });

      it('should have Base getData function defined.', () => {
        expect(this.component.getData).toBeDefined();
      });
    });
  }
}

【讨论】:

    猜你喜欢
    • 2020-08-19
    • 1970-01-01
    • 2016-06-14
    • 2017-09-27
    • 1970-01-01
    • 2022-01-23
    • 2020-11-25
    • 1970-01-01
    相关资源
    最近更新 更多