typescript - 使用 Jest/Typescript 和虚拟函数测试 fs 库函数

标签 typescript testing jestjs

在尝试测试使用 fs 模块的库函数时,我在 this question 中获得了帮助在没有模拟的情况下更好地测试功能,我同意 @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 pass,它不喜欢 as any 布局,并且更喜欢 Variable:type 表示法。

最佳答案

您的代码永远不会返回 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;

此外,您的 stub 需要抛出以模拟相同的行为。

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 ,但我个人认为这是矫枉过正。

通常不鼓励使用类型断言,因为它只是告诉编译器,“嘿,我知道你认为 xX,但我知道它实际上是 Y,所以让我们将其视为 Y” ,所以你基本上失去了类型检查的好处。

但特别是对于 mock 和 stub,没关系,因为你有意识地意识到你在“伪造”它,并且你有测试来备份丢失的类型检查。

第二种方式涉及接口(interface)隔离原则(ISP,The I in SOLID principles)。

这个想法是询问你实际需要什么,而不是获取整个类型/接口(interface)。

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

您的测试不再需要进行类型断言。

请注意,我必须在这里使用类型断言,因为 X.y: <type> = value不是有效语法。

我能做到:

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

但这很愚蠢。

这样做的好处是它更精确,并能密切跟踪您的实际使用情况。

这样做的缺点是有点乏味。我希望控制流分析将来可以自动为我做这件事。 :)

关于typescript - 使用 Jest/Typescript 和虚拟函数测试 fs 库函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52725339/

相关文章:

angular - 如何在基于 Angular2 angular-cli 的项目中包含明确类型的文件

typescript - 将由许多文件/模块组成的 TypeScript 项目编译为单个文件

angular - 属性 '...' 没有初始化器,在构造函数中未明确分配

ruby - 如何测试网络抓取应用程序?

user-interface - 在 Xamarin UI 测试中需要帮助

unit-testing - 如何在java中测试物化 View

reactjs - 如何使用 react-testing-library 和 jest 测试链接

react-native - Jest 没有覆盖一堆文件中的最后一个 import 语句

javascript - 如何测试中止的函数?

Angular 单元测试不初始化 ag-Grid