Тестирование функции библиотеки fs с помощью Jest / Typescript и фиктивной функции - PullRequest
0 голосов
/ 09 октября 2018

При попытке протестировать библиотечную функцию, использующую модуль fs, мне помогли в этом вопросе , чтобы лучше протестировать функциональность, без насмешек, что, как я согласился, @unional было лучшим методом.

Я пытаюсь сделать то же самое с методом accessSync, но он не работает аналогичным образом и нуждается в некоторых изменениях для тестирования.

Мой код, следуя изменениям, предложенным @unional:

import fs from 'fs';
export function AccessFileSync(PathAndFileName: string):boolean {
    if (PathAndFileName === undefined || PathAndFileName === null || PathAndFileName.length === 0) {
        throw new Error('Missing File Name');
    }
    try {
        AccessFileSync.fs.accessSync(PathAndFileName, fs.constants.F_OK | fs.constants.R_OK);
    } catch {
        return false;
    }
    return true;
}
AccessFileSync.fs = fs;

Теперь, чтобы попытаться проверить это, я бы:

describe('Return Mock data to test the function', () => {
    it('should return the test data', () => {
        // mock function
        AccessFileSync.fs = {
            accessSync: () => { return true; }
        } as any;

        const AccessAllowed:boolean = AccessFileSync('test-path');      // Does not need to exist due to mock above
        expect(AccessFileSync.fs.accessSync).toHaveBeenCalled();
        expect(AccessAllowed).toBeTruthy();
    });
});

Это работает для первого теста, но последующие тесты, изменяя тест, не получают новыйзначение.Например:

describe('Return Mock data to test the function', () => {
    it('should return the test data', () => {
        // mock function
        AccessFileSync.fs = {
            accessSync: () => { return true; }
        } as any;

        const AccessAllowed:boolean = AccessFileSync('test-path');      // Does not need to exist due to mock above
        expect(AccessFileSync.fs.accessSync).toHaveBeenCalled();
        expect(AccessAllowed).toBeTruthy();
    });
});
describe('Return Mock data to test the function', () => {
    it('should return the test data', () => {
        // mock function
        AccessFileSync.fs = {
            accessSync: () => { return false; }
        } as any;

        const AccessAllowed:boolean = AccessFileSync('test-path');      // Does not need to exist due to mock above
        expect(AccessFileSync.fs.accessSync).toHaveBeenCalled();
        expect(AccessAllowed).toBeFalsy();  // <- This Fails
    });
});

Кроме того, я хотел бы получить проход tslint, который не похож на макет as any, и предпочел бы нотацию Variable:type.

1 Ответ

0 голосов
/ 09 октября 2018

Ваш код никогда не возвращается false:

import fs from 'fs';
export function AccessFileSync(PathAndFileName: string): boolean {
  if (PathAndFileName === undefined || PathAndFileName === null || PathAndFileName.length === 0) {
    throw new Error('Missing File Name');
  }
  try {
    AccessFileSync.fs.accessSync(PathAndFileName, fs.constants.F_OK | fs.constants.R_OK);
  }
  catch {
    return false; // here
  }
  return true;
}
AccessFileSync.fs = fs;

Кроме того, ваша заглушка должна быть сброшена для имитации того же поведения.

describe('Return Mock data to test the function', () => {
  it('should return the test data', () => {
    // mock function
    AccessFileSync.fs = {
      accessSync: () => { throw new Error('try to mimic the actual error') }
    };

    const AccessAllowed: boolean = AccessFileSync('test-path');
    expect(AccessAllowed).toBeFalsy(); 
  });
});

Что касается ошибки lint,Есть два способа справиться с этим.

Первый - это утверждение типа, то есть то, что вы делаете, и вы можете привести его к чему угодно, например, as typeof fs, но лично я думаю, что этоoverkill.

Утверждение типа, как правило, не рекомендуется, поскольку оно просто говорит компилятору: «Эй, я знаю, вы думали, что x - это X, но я знаю, что на самом деле это Y, поэтому давайте рассмотрим егокак Y ", так что вы в основном потеряли преимущество проверки типов.

Но специально для макета и заглушки, это нормально, потому что вы осознанно знаете, что вы его« подделываете », и у вас есть тестдля резервного копирования потерянной проверки типов.

Второй способ связан с принципом разделения интерфейсов (ISP, принципы I в SOLID).

Идея состоит в том, чтобы спросить, что вам действительно нужно,вместо того, чтобы приобрести весь тыpe / interface.

AccessFileSync.fs = fs as Pick<typeof fs, 'accessSync'>

Вашему тесту больше не нужно делать утверждение типа.

Обратите внимание, что здесь я должен использовать утверждение типа, потому что X.y: <type> = value не является допустимым синтаксисом.

Я могу сделать это:

const fs2: Pick<typeof fs, 'accessSync'> = fs
AccessFileSync.fs = fs2

, но это просто глупо.

Плюс в том, что он более точный и точно соответствует тому, что вы на самом деле используете.

Недостатком является то, что это немного более утомительно.Я хотел бы, чтобы анализ потока управления мог сделать это автоматически для меня в будущем.:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...