mocking - Hur man mockar en TypeScript-klass med Vitest


Jag har en klass A som importerar klass B från en annan modul och skapar en instans av den. I mitt test för klass A skulle jag vilja stubba/mocka några av metoderna i klass B.

Exempel på kod:

// Formatter.ts
export class Formatter {
   format(msg: string): string {
     return `--- [INFO] ${msg}\n`;
   }
}

// FormattedStore.ts
import {Formatter} from '@/Formatter'
export class FormattedStore implements Store {
   public store: string[];
   construct() {
     this.formatter = new Formatter();
     this.store = [];
   }

   write(msg: string): void {
      this.store.push(this.formatter.format(msg));
   }
}

// FormattedStore.spec.ts
import {FormattedStore} from '@/FormattedStore';
import {Formatter} from '@/Formatter'
import {vi, expect, test} from 'vitest';

vi.mock( '@/Formatter', () => ({ 
 Formatter: vi.fn() // What's the correct and type-safe way to mock this?
}));

test('it stores formatted message', () => {
   //  How do I mock the formatter here with the return 'formatted test message'?
   const store = new FormattedStore();
   store.write('TestMessage');

   expect(store.store[0]).toBe('formatted test message');
})

Jag vet att jag kunde använda konstruktörinjektion istället för att mocka modulen, men jag har ett fall där det inte är möjligt.

Svar #1

Paketet vitest-mock-extended löser detta:

// FormattedStore.spec.ts
import {mock} from 'vitest-mock-extended';
import {FormattedStore} from '@/FormattedStore';
import {Formatter} from '@/Formatter'
import {vi, expect, test} from 'vitest';

vi.mock( '@/Formatter', () => ({ 
 Formatter: mock<Formatter>() // Mock class here
}));

test('it stores formatted message', () => {
   Formatter.format.mockReturnValue('formatted test message');  // provide return values here
   const store = new FormattedStore();
   store.write('TestMessage');

   expect(store.store[0]).toBe('formatted test message');
})

Relaterade artiklar