9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Jestで現在実行中のテストケースの名前を取得する

Last updated at Posted at 2018-09-27

Jestで単体テストをやっていて、現在実行中のテストケースの名前を取得したいと思ったことはないですか?はい、私は思いました。現在実行中のテストケースの名前が取得できれば例えばこんなことができるはずです。

describe('example', () => {
  beforeEach(async () => {
    // testCaseName(これから実行するテストケースの名前)が取れれば...
    // executeSqlは指定したsqlファイルを実行する関数だと思ってください
    await executeSql(testCaseName + '.sql')
  })

  test('test1', () => {
    // test1.sqlが実行された後
  })

  test('test2', () => {
    // test2.sqlが実行された後
  })
})

あとは、適当な場所にtest1.sqltest2.sqlを用意しておけば、テストケースが実行される前に一律、それぞれのテストケースの前処理のためのSQLを流し込むことができるでしょう。afterEachによる後処理も同様です。

describeやtestの返り値

一応、describetestは返り値として、名前等を含むメタ情報を取得できます。

const example = describe('example', () => {
  beforeEach(() => {
    // describeのメタ情報
    console.log(example)
  })

  const test1 = test('test1', () => {
    // testのメタ情報
    console.log(test1)
    expect(1 + 1).toBe(2)
  })
})

中を見てみるとdescriptionというものがあって、desribetestの名前がわかります。

// describe(一部)
Suite {
  id: 'suite1',
  description: 'example',
  throwOnExpectationFailure: false
}
  
// test(一部)
Spec {
  resultCallback: [Function],
  id: 'spec0',
  description: 'test1'
}

ただ、これでは現在実行中のテストケースがどれなのかわかりませんし、正直使い所がわからんです。

Jasmineのカスタムレポーターを使う

実はJestはJasmineを元にしている(最近知った)のでJasmineの機能を使えたりします。なので、Jestが入っていれば追加でJasmineをインストールする必要もありません。そして、Jasmineにはカスタムレポーターというものがあって、テストのライフサイクルの各タイミングでフックすることができます。キーを各フックポイントの名前、値をそのタイミングで実行したい関数にしたオブジェクトを作り、jasmine.getEnv().addReporterに渡します。

const reporter = {
  jasmineStarted(suiteInfo) {
    console.log('jasmineStarted')
    console.log(suiteInfo)
  },
  suiteStarted(result) {
    console.log('suiteStarted')
    console.log(result)
  },
  specStarted(result) {
    console.log('specStarted')
    console.log(result)
  },
  specDone(result) {
    console.log('specDone')
    console.log(result)
  },
  suiteDone(result) {
    console.log('suiteDone')
    console.log(result)
  },
  jasmineDone() {
    console.log('jasmineDone')
  }
}

jasmine.getEnv().addReporter(reporter)

各フックポイントは以下のタイミングで実行されます。

フック タイミング 関数で受け取る引数
jasmineStarted テスト全体が開始するとき suiteInfo(テストケースの合計数)
suiteStarted 各describeが開始するとき result(describeのメタ情報)
specStarted 各testが開始するとき result(testのメタ情報)
specDone 各testが終了したとき result(testのメタ情報、テストの成功・失敗等の情報も追加される)
suiteDone 各describeの全てのテストが終了したとき result(describeのメタ情報、テストの成功・失敗等の情報も追加される)
jasmineDone テスト全体が終了したとき なし

suiteStartedspecStartedのコールバック関数の引数で受け取れるオブジェクトにはそのdescribeやtestの名前の情報も含まれていて、しかも各テストケースが開始するタイミングで毎回呼び出されるので、これは使えそうですね!

// specStartedのresultの例
{
  id: 'spec0',
  description: 'test1',
  fullName: 'example test1',
  failedExpectations: [],
  passedExpectations: [],
  pendingReason: '',
  testPath: '/hogehoge/hoge.test.js'
}

ちなみにdescriptionfullNameと2つありますが、fullNameの方は親以上のdescribeの名前もスペース区切りで含まれるようになっています。「desc1というdescribeの中にあるdesc2というdescribeの中にあるtest1というtest」の場合ですと、fullNameはdesc1 desc2 test1といった感じになります。

カスタムレポーターで現在実行中のテストケースの名前を取得する

さて、冒頭にお見せしたものをカスタムレポーターで実現してみましょう。

let testCaseName

const reporter = {
  // 各testが開始するタイミングで呼び出される
  specStarted(result) {
    testCaseName = result.description
  }
}

jasmine.getEnv().addReporter(reporter)

describe('example', () => {
  beforeEach(async () => {
    await executeSql(testCaseName + '.sql')
  })

  test('test1', () => {
    // test1.sqlが実行された後!
  })

  test('test2', () => {
    // test2.sqlが実行された後!
  })
})

specStartedで各testが開始するタイミングでフックし、そのtestの名前をtestCaseNameに代入しています。テストケースの名前を保持するいい方法が思いつかなかったので、とりあえずグローバル変数にぶちこんでいます。それをbeforeEachで参照しているという形ですね。もっとイケてる方法を知っている偉い人いたら教えてください。

いかがでしたでしょうか。今回紹介した各テストケース用のSQLを流し込むという用途以外にもいろいろ使えそうですね。ぜひ活用してみてください。

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?