重复使用Jest单元测试

20

我正在尝试使用Jest测试几个数据库实现。为了帮助测试这些实现,我首先想出了一组针对API的单元测试,这些实现都应该实现该API。

我目前正在努力将这两个实现传递给测试套件。

以下是一个最简单形式的(虚拟)MongoDB实现:

class MongoDB {
  async query () {
    console.warn(`This is a dummy function.`)
  }

  async connect () {
    // The real connect takes some time..instead we just simulate it
    await new Promise((resolve, reject) => {
      setTimeout(resolve, 300)
    })
  }
}

这是我的一些测试代码片段:

let db
beforeAll(async () => {
  db = new MongoDB()
  await db.connect()
  console.log(`mongoDB ready`)
})

async function testDB (db) {
  describe('Basic', async () => {
    test('Valid instance', async () => {
      expect(db).toBeTruthy()
      expect(db.query).toBeTruthy()
    })
  })
}

describe('Tests', async () => {
  console.log(`Running testDB`)
  testDB(db) // Have also unsuccessfully tried changing this to: return testDB(db)
})

我采用这种方法的目的是将所有测试包装在testDB函数中,并使用不同的实现进行调用。例如,testDB(new MongoDB())testDB(new MemoryDB())等。

然而,这似乎没有按预期工作。 上述代码会导致以下错误:

TestsBasicValid instance

    expect(received).toBeTruthy()

    Expected value to be truthy, instead received
      undefined

console.log语句的顺序似乎表明测试在db初始化之前运行。

  console.log mongo.test.js:20
    Running testDB

  console.log mongo.test.js:7
    mongoDB ready

整个示例以及生成的输出结果可以在 repl.it 上复制。

如何重复使用单元测试来测试多个实现,而不必重复编写测试并维护两个版本?

1个回答

28

今天我遇到了同样的需求。以下是一种方式,改编自 TypeScript ,但您可以理解思路:

// common/service.test.js
export const commonServiceTests = (name, impl) => {
  describe(`Common tests for ${implName}`, () => {
    // pile your tests here
    test('test1', () => { ... });
    test('test2', () => { ... });
    test('test3', () => { ... });
  });
}

// just to avoid warning, that no tests in test file
describe('Common tests for CommonService implementations', () => {
  test('should be used per implementation', () => {});
});

并且对于您的每个实现:

// inmemory/service.test.js
import { commonServiceTests } from '../common/service.test';
import ...; // your implementation here

const myInMemoryService = ...; // initialize it

commonServiceTests('InMemory', myInMemoryService);

那么,common/service.test.js 中定义的所有测试将在每个实现测试中执行。

如果您的初始化是async(这很可能),那么您的共享测试也应该是async。然后:

// common/service.test.js
export const commonServiceTests = (name, impl: Promise) => {
  describe(`Common tests for ${implName}`, () => {
    // pile your async tests here
    test('test1', async () => {
      const svc = await impl;
      return await svc.doSomthingPromisy();
    });
    test('test2', () => { ... });
    test('test3', () => { ... });
  });
}

我使用了这个确切的流程,并且在 jest 中运行得非常好,但是当我们尝试在 playwright-test 中使用此方法进行测试注释(skip、slow 等)时,它会挂起。 - rdrw
似乎不需要启用空测试以避免警告,例如只需跳过它 test.skip('应根据实现使用', () => {}); - thejhh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接