我应该测试这段代码吗? (立即方法调用分配给 class 成员)

Should I test this code? (immediate method call assignment to class member)

class MyClassComponent {
  hasAccess = this.hasAccessToSomething();

  constructor(private numberService: NumberService) {}

  private hasAccessToSomething(): boolean {
    return this.numberService.getNumber() > 5;
  }
}

我应该根据 numberService.getNumber() 值测试 hasAccess 等于 false 还是 true 吗?这是一个初始 class 状态,我调用了一个私有方法,一个不应该被测试的方法,并将其值分配给我的 public class 成员。

如果答案是肯定的 - 如何使用 jasmine/jest 和 TestBed 来做到这一点?

let component: MyClassComponent;

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [
      MyClassComponent,
      NumberService
    ]
  });

  component = TestBed.inject(MyClassComponent);
});

我可以模拟 NumberService.getNumber 方法,但问题是在创建模拟后,我无法重新初始化 hasAccess 赋值。例如,我可以调用 this.hasAccessToSomething ngOnInit 然后测试 hasAccess 值再次调用 ngOnInit 但我不想为了测试目的而使 class 复杂化。使用如此简单的 class 我可以摆脱 TestBed 并使用 new MyClassComponent 重新初始化组件,但让我们想象一下这个 class 更大,依赖更多。

你会怎么做?

您可以将 jasmine.Spy 用于此目的并将 hasAccess 变成 getter 属性:

export class MyClassComponent {
  public get hasAccess(): boolean {
    return this.hasAccessToSomething()
  }
  ...

在你的测试中:

describe('MyClassComponent', () => {
  beforeEach(async () => {
    TestBed.configureTestingModule({
    providers: [
      MyClassComponent,
      NumberService
    ]
  });
    ...
  })

  it('should have access if numberService.getNumber() returns more than 5', () => {
    spyOn(TestBed.inject(NumberService), 'getNumber').and.returnValue(6)
    expect(component.hasAccess).toBeTrue()
  })


  it('should not have access if numberService.getNumber() returns less than 5', () => {
    spyOn(TestBed.inject(NumberService), 'getNumber').and.returnValue(4)
    expect(component.hasAccess).toBeFalse()
  })

})

如果您不想hasAccess变成getter属性那么您应该在组件的创建范围之前mocking/spying 在服务上使用嵌套描述块:

describe('MyComponent...', () => {

  beforeEach(() =>  /*build the module*/)

  describe('when NumberService.getNumber returns more than 5', () => {
    beforeEach(() => {
      spyOn(TestBed.inject(NumberService), 'getNumber').and.returnValue(6)
      component = ...
    })

    it('should have access', () => expect(component.hasAccess).toBeTrue())
  })
  // Symmetric for less than 5

我相信这就是您要找的

let component: MyClassComponent;

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [MyClassComponent, NumberService],
  });
});

describe("with default NumberService result", () => {
  beforeEach(() => {
    component = TestBed.inject(MyClassComponent);
  });

    it('should ....',()=>{...})
});

describe("with mocked NumberService result", () => {
  beforeEach(() => {
    TestBed.overrideProvider(NumberService, {
      useValue: { getNumber: () => 999 },
    });
    component = TestBed.inject(MyClassComponent);
  });

    it('should ....',()=>{...})
});