Создать фиктивный сервис (объект) Jest с одним методом, возвращающим значение

В угловом среде, как можно очень легко создать в Шутках в Передразнивала службу для объекта службы , возвращающего значение конкретного?

Словами в стиле Mockito:

      // beforeEach: 
// setup my Angular component with a service component myMockService

// Test 1: 
// when(myMockService.doSomething()).thenReturnValue(10);
// expect(myComponent.getBalance()).toEqual( "Your balance: 10"); 

Я изучил документацию Jest, но не нашел очень простого подхода. Тот, что ниже, подходит, но, возможно, у вас есть лучший подход. Поскольку в Jest есть средства для имитации, я не буду использовать, например, библиотеку 'ng-mock'.

Мой упрощенный компонент Angular:

      @Component({
  selector: 'app-servicecounter',
  templateUrl: './servicecounter.component.html'
})
export class ServicecounterComponent {
  private myValue: number = 1;
  constructor(private counterService: CounterService) { }
  public doSomething(): void {
    // ...
    myValue = this.counterService.getCount();
  }
}

Это упрощенная услуга:

      @Injectable()
export class CounterService {
  private count = 0;
  constructor() { }
  public getCount(): Observable<number> {
    return this.count;
  }
  public increment(): void { 
    this.count++;
  }
  public decrement(): void {
    this.count--;
  }
  public reset(newCount: number): void {
    this.count = newCount;
  }
}

Попробуйте 1: рабочее решение: с jest.genMockFromModule:

      beforeEach(async () => {
  mockCounterService = jest.genMockFromModule( './counterservice.service');
  mockCounterService.getCount = jest.fn( () => 3);
  mockCounterService.reset = jest.fn(); // it was called, I had to mock.fn it. 
  await TestBed.configureTestingModule({
    declarations: [ServicecounterComponent],
    providers: [ { provide: CounterService, useValue: mockCounterService }],
  }).compileComponents();
  fixture = TestBed.createComponent(ServicecounterComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});

it('shows the count', () => {
  setFieldValue(fixture, 'reset-input', String(currentCount));
  click(fixture, 'reset-button');
  expect(mockCounterService.getCount()).toEqual( 3);
  expect( mockCounterService.getCount).toBeCalled();
});

Попробуйте 1B: замените jest.genMockFromModule на jest.createMockFromModule : работает одинаково хорошо.

Попробуйте 2: заранее создайте имитацию объекта: не сработало

      jest.mock( "./counterservice.service");

beforeEach(async () => {
  // Create fake
  mockCounterService = new CounterService();
  (mockCounterService.getCount() as jest.Mock).mockReturnValue( 0);
  await TestBed.configureTestingModule({
    declarations: [ServicecounterComponent],
    providers: [{ provide: CounterService, useValue: mockCounterService }],
  }).compileComponents();

  fixture = TestBed.createComponent(ServicecounterComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
}); 

it('shows the count', () => {
  // do something that will trigger the mockCountService getCount method.  
  expect(mockCounterService.getCount).toEqual( 0);
});

Это не работает, выдает ошибку:

      > (mockCounterService.getCount() as jest.Mock).mockReturnValue( 0); 
> Cannot read property 'mockReturnValue' of undefined

Попробуйте 3: с .fn(). Недостатком является то, что исходный класс может измениться, тогда объект тестирования ДОЛЖЕН измениться.

      beforeEach(async () => {
  mockCounterService = {
    getCount: jest.fn().mockReturnValue( 0),
    increment: jest.fn,
    decrement: jest.fn(),
    reset: jest.fn
  };
  await TestBed.configureTestingModule({
    declarations: [ServicecounterComponent],
    providers: [{ provide: CounterService, useValue: mockCounterService }],
  }).compileComponents();
});
  
it( '... ', () => {
  // ... 
  expect(mockCounterService.reset).toHaveBeenCalled();
});

На этот раз ошибка:

      > Matcher error: received value must be a mock or spy function ...
> expect(mockCounterService.reset).toHaveBeenCalled();

Как я могу увидеть, что метод был вызван?

То же самое с конкретным аргументом?

Возможно ли получить серию возвращаемых значений?

1 ответ

Вам нужно использоватьMockBuilderиздеваться над сервисом иMockInstanceнастроить его.

Также getCountявляется наблюдаемым, поэтому его макет должен возвращаться Subject, которым мы можем манипулировать.

      // to reset MockInstance customizations after tests
MockInstance.scope();

// to use jest.fn on all mocks https://ng-mocks.sudo.eu/extra/auto-spy
beforeEach(() => ngMocks.autoSpy('jest'));
afterEach(() => ngMocks.autoSpy('reset'));

beforeEach(() => MockBuilder(ServicecounterComponent, CounterService));

it('testing', () => {
  // this is our control of observable of getCount 
  const getCount$ = new Subject<number>();
  // now we need to return it when getCount is called
  const getCount = MockInstance(CounterService, 'getCount', jest.fn())
    .mockReturnValue(getCount$);

  // now we can use it in our test.
  const fixture = MockRender(ServicecounterComponent);
  ngMocks.click('.reset-button');
  expect(getCount).toHaveBeenCalled();

  getCount$.next(3);
  expect(ngMocks.formatText(fixture)).toContain('3');
});
Другие вопросы по тегам