如何测试angular组件间传值

前言

咱们知道angular组件间通信有多种方法,其中最经常使用的一种方法就是借助于 @Input 和 @Output 进行通信。具体如何通信请参考angular组件间通信,本文再也不赘述,咱们来说讲关于此方法如何进行单元测试。git

建立假组件

咱们单元测试父组件与子组件的的交互是否符合咱们的要求,咱们在父组件进行测试,就须要模拟一个假的子组件出来,这样排除其余因素对测试的影响。
好比如今我在分页组件里写了一个每页大小选择组件,如今要测试一下组件间交互。如今分页组件就是咱们的父组件,每页大小组件就是咱们的子组件。咱们如今须要去模拟一个假的子组件出来。咱们先模拟一个假模块出来。
咱们的子组件在core模块里,咱们在core模块下创造一个core-testing模拟模块。再在core-testing模块下创造一个core组件,由于咱们是一个模拟模块,咱们只须要ts文件便可。segmentfault

@Component({
  selector: 'app-size',
  template: `
    <p>
       size-select works!
    </p>
  `,
  styles: []
})
export class SizeComponent implements OnInit {
    constructor() {
    }

    ngOnInit() {
    }
}

为了咱们能够在父组件的测试文件中获得模拟的子组件,咱们还须要一个controller,在core-testing文件夹下建立一个core-testing-controller.ts文件。CoreTestingController类继承TestingControllerapp

export class CoreTestingController extends TestingController {
}

同时在咱们的core-testing.module里声明CoreTestingController为提供者async

providers: [
    CoreTestingController
  ]

此时咱们的目录树ide

core-testing git:(134) ✗ tree   
.
├── core-testing-controller.ts
├── core-testing.module.ts
├── page
│   └── page.component.ts
└── size
    └── size.component.ts

由于咱们是模拟的子组件,因此咱们应该添加子组件的@Input 和 @Output,同时在构造函数里把这个模拟的子组件添加到CoreTestingController里。函数

export class SizeComponent implements OnInit {
  @Input() size: number;

  @Output() onChangeSize = new EventEmitter<number>();

  constructor(private controller: CoreTestingController) {
    this.controller.addUnit(this);
  }
}

此时咱们的准备工做就完成了。单元测试

单元测试

首先咱们引入假组件并声明提供者测试

import {CoreTestingController} from '../core-testing/core-testing-controller';
import {SizeComponent} from '../core-testing/size/size.component';

beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ PageComponent, SizeComponent ],
      imports: [FormsModule],
      providers: [
        CoreTestingController
      ]
    })
    .compileComponents();
  }));

我大家这里引入的是咱们创造的假的SizeComponent,由于咱们父组件与子组件在同一个模块里,因此咱们直接引入SizeComponent就能够。
此时咱们父组件想要子组件时就会使用假的子组件。
咱们先断言@Input,咱们断言父组件的值与咱们假的子组件值相等this

it('选择每页大小', () => {
    const controller = TestBed.get(CoreTestingController) as CoreTestingController;
    const sizeComponent = controller.get(SizeComponent) as SizeComponent;
    expect(sizeComponent.size).toBe(component.size);
  });

咱们这里的get方法就对应的咱们以前的构造函数的addUnit方法,具体参考TestingController类定义的方法。
而后咱们再断言子组件向父组件@Output也没有问题,咱们先spyon父组件接收子组件值的方法,而后定义一个变量并传给父组件,而后断言父组件接收到的值与子组件传的值相同。spa

spyOn(component, 'onSizeSelected');
const emitSize = 4;
sizeComponent.onChangeSize.emit(emitSize);
expect(component.onSizeSelected).toHaveBeenCalledWith(4);

这时咱们就达到了咱们测试的目的。
咱们启动测试,发现咱们原本的选择下拉框变成了文字,这就是咱们假的子组件的效果。
image.png

总结

咱们进行单元测试,就须要除被测组件外,其余引用组件尽可能为假,才能达到咱们的目的。