如何在Angular单元测试里,对class protected方法进行测试

简介: 我的service class里有一个protected方法,我想在单元测试里对其进行测试:

image.png

一种思路是,可以沿用Java里测试protected方法的变通方式,即创建一个新的sub class,继承包含该protected方法的class,然后在子类里新建一个公有方法作为wrapper之用,实现逻辑只有一行,就是调用父类的protected方法。

例子如下:

image.png

import { Injectable } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { EntitiesModel } from '@spartacus/core';
import {
  B2BUnitNode,
  B2BUnitTreeNode,
  OrgUnitService,
} from '@spartacus/organization/administration/core';
import { TableService, TableStructure } from '@spartacus/storefront';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { UnitItemService } from './unit-item.service';
import { UnitListService } from './unit-list.service';
import { TREE_TOGGLE } from './unit-tree.model';
import { UnitTreeService } from './unit-tree.service';
import createSpy = jasmine.createSpy;
function verifyExpandedAll({ values }: EntitiesModel<B2BUnitTreeNode>) {
  expect(values.length).toEqual(7);
  values.forEach((element) => {
    expect(element.expanded).toBeTrue();
  });
}
function verifyCollapsedAll({ values }: EntitiesModel<B2BUnitTreeNode>) {
  const root = values[0];
  expect(values.length).toEqual(1);
  expect(root.uid).toEqual(mockedTree.id);
  expect(root.expanded).toBeFalse();
  expect(root.depthLevel).toEqual(0);
  expect(root.count).toEqual(mockedTree.children.length);
}
const codeKey = 'uid';
const mockedTree = {
  id: 'Rustic',
  name: 'Rustic',
  active: true,
  children: [
    {
      id: 'Rustic Services',
      name: 'Rustic Services',
      parent: 'Rustic',
      active: true,
      children: [
        {
          active: true,
          children: [],
          id: 'Services West',
          name: 'Services West',
          parent: 'Rustic Services',
        },
        {
          active: true,
          children: [],
          id: 'Services East',
          name: 'Services East',
          parent: 'Rustic Services',
        },
      ],
    },
    {
      id: 'Rustic Retail',
      name: 'Rustic Retail',
      parent: 'Rustic',
      active: true,
      children: [
        {
          active: true,
          id: 'Custom Retail',
          name: 'Custom Retail',
          parent: 'Rustic Retail',
          children: [
            {
              active: true,
              children: [],
              id: 'Test',
              name: 'TestUnit',
              parent: 'Custom Retail',
            },
          ],
        },
      ],
    },
  ],
};
const mockedTreeBeforeConvert = {
  id: 'Rustic',
  name: 'Rustic',
  active: true,
  children: [
    {
      id: 'test3',
      name: 'test3',
      parent: 'Rustic',
      active: true,
      children: [],
    },
    {
      id: 'test1',
      name: 'test1',
      parent: 'Rustic',
      active: true,
      children: [],
    },
    {
      id: 'test2',
      name: 'test2',
      parent: 'Rustic',
      active: true,
      children: [],
    },
  ],
};
const mockedTreeAfterConvert = {
  pagination: {
    totalResults: 4,
  },
  values: [
    {
      active: true,
      children: [
        {
          id: 'test1',
          name: 'test1',
          parent: 'Rustic',
          active: true,
          children: [],
        },
        {
          id: 'test2',
          name: 'test2',
          parent: 'Rustic',
          active: true,
          children: [],
        },
        {
          id: 'test3',
          name: 'test3',
          parent: 'Rustic',
          active: true,
          children: [],
        },
      ],
      count: 3,
      depthLevel: 0,
      expanded: false,
      id: 'Rustic',
      name: 'Rustic',
      uid: 'Rustic',
    },
  ],
};
const treeToggle$ = new BehaviorSubject(
  new Map().set(mockedTree.id, TREE_TOGGLE.EXPANDED)
);
class MockUnitService {
  getTree(): Observable<B2BUnitNode> {
    return of(mockedTree);
  }
}
@Injectable()
export class MockTableService {
  buildStructure(type): Observable<TableStructure> {
    return of({ type });
  }
}
export class MockUnitTreeService {
  treeToggle$ = treeToggle$.asObservable();
  initialize = createSpy('initialize');
  getToggleState = createSpy('getToggleState')
    .withArgs(mockedTree.id)
    .and.returnValue(treeToggle$.value?.get(mockedTree.id));
  isExpanded = createSpy('isExpanded').and.returnValue(false);
}
export class UnitListServiceForSortTest extends UnitListService {
  public convertListItemWrapper(unit: B2BUnitNode) {
    return this.convertListItem(unit);
  }
}
describe('UnitListService', () => {
  let service: UnitListService;
  let treeService: UnitTreeService;
  describe('with table config', () => {
    beforeEach(() => {
      TestBed.configureTestingModule({
        providers: [
          {
            provide: UnitListService,
            useClass: UnitListServiceForSortTest,
          },
          {
            provide: UnitTreeService,
            useClass: MockUnitTreeService,
          },
          {
            provide: OrgUnitService,
            useClass: MockUnitService,
          },
          {
            provide: TableService,
            useClass: MockTableService,
          },
          {
            provide: UnitItemService,
            useValue: {
              key$: of(mockedTree.id),
            },
          },
        ],
      });
      service = TestBed.inject(UnitListService);
      treeService = TestBed.inject(UnitTreeService);
    });
    it('should inject service', () => {
      expect(service).toBeTruthy();
    });
    it('should return "code" key', () => {
      expect(service.key()).toEqual(codeKey);
    });
    it('should get collapsed all items structure', () => {
      let result: EntitiesModel<B2BUnitTreeNode>;
      service.getData().subscribe((table) => (result = table));
      verifyCollapsedAll(result);
    });
    it('should get expanded all items structure', () => {
      let result: EntitiesModel<B2BUnitTreeNode>;
      treeService.isExpanded = createSpy().and.returnValue(true);
      service.getData().subscribe((table) => (result = table));
      verifyExpandedAll(result);
    });
    it('should automatically sort unit tree by name', () => {
      const serviceForSort = service as UnitListServiceForSortTest;
      const convertedTree = serviceForSort.convertListItemWrapper(
        mockedTreeBeforeConvert
      );
      expect(convertedTree).toEqual(mockedTreeAfterConvert);
    });
  });
});


相关文章
|
5天前
|
Java 测试技术 持续交付
自动化测试实践:从单元测试到集成测试
【6月更文挑战第28天】-单元测试:聚焦代码最小单元,确保每个函数或模块按预期工作。使用测试框架(如JUnit, unittest),编写覆盖所有功能和边界的测试用例,持续集成确保每次变更后自动测试。 - 集成测试:关注模块间交互,检查协同工作。选择集成策略,编写集成测试用例,模拟真实环境执行测试,整合到CI/CD流程以持续验证软件稳定性。 自动化测试提升软件质量,降低成本,加速开发周期,是现代软件开发不可或缺的部分。
|
3天前
|
Java 测试技术 数据库
Java单元测试与集成测试的最佳实践
Java单元测试与集成测试的最佳实践
|
7天前
|
测试技术 Android开发 流计算
软件测试之 单元测试
软件测试之 单元测试
10 2
|
23天前
|
IDE 测试技术 持续交付
Python作为一种简洁、易读且功能强大的编程语言,其自动化测试和单元测试框架的丰富性和易用性为开发者提供了极大的便利
【6月更文挑战第10天】本文探讨了Python自动化测试与单元测试框架在提升代码质量和效率中的作用。Selenium、Appium和pytest是常用的自动化测试框架,分别支持Web和移动应用的测试。unittest是Python的标准单元测试框架,提供断言方法和测试组织结构。通过制定测试计划、编写高质量测试用例、持续集成与测试、以及有效利用测试报告,开发者能提高代码质量和开发效率。
30 1
|
5天前
|
Java 测试技术 开发者
Java中的单元测试与集成测试策略
Java中的单元测试与集成测试策略
|
9天前
|
监控 druid Java
Springboot用JUnit测试接口时报错Failed to determine a suitable driver class configure a DataSource: ‘url‘
Springboot用JUnit测试接口时报错Failed to determine a suitable driver class configure a DataSource: ‘url‘
18 0
|
2月前
|
测试技术
测试基础 Junit单元测试框架
测试基础 Junit单元测试框架
23 2
测试基础 Junit单元测试框架
|
2月前
|
API 开发者
Angular Component class ɵfac 的属性介绍
Angular Component class ɵfac 的属性介绍
|
2月前
|
监控 数据可视化 IDE
python自动化测试实战 —— 单元测试框架
python自动化测试实战 —— 单元测试框架
38 2
|
29天前
|
测试技术 Python
【Python自动化测试】:Unittest单元测试与HTMLTestRunner自动生成测试用例的好帮手
【Python自动化测试】:Unittest单元测试与HTMLTestRunner自动生成测试用例的好帮手
18 0