Jestのカバレッジ計測について(モック編)
Jestのカバレッジ計測について - 経験は何よりも饒舌 で、「JestはJestのAPIを用いたテストに対してカバレッジを計測しているのではなく、テストで呼び出されたか否かでカバレッジを計測している」ことが分かったけど一応モックの場合も調査してみる。
モック自体は Jest のモック関数を整理する - 経験は何よりも饒舌 で整理している。
次のコードで調査していく。
const obj = { random: function () { return Math.random(); }, randomPlusOne: function () { return Math.random() + 1; }, }; module.exports = obj;
まずはモックを使わずにテストしてみる。
const obj = require("./sample"); describe("sample", () => { it("random", () => { expect(obj.random()).toBe(1); }); it("randomPlusOne", () => { expect(obj.randomPlusOne()).toBe(2); }) })
予想通りテストは通らないが、カバレッジは100%になる。
$ npm run test > jest-playground@1.0.0 test > jest --collectCoverage FAIL ./sample.test.js sample ✕ random (4 ms) ✕ randomPlusOne (1 ms) ● sample › random expect(received).toBe(expected) // Object.is equality Expected: 1 Received: 0.0018626031125137388 6 | describe("sample", () => { 7 | it("random", () => { > 8 | expect(obj.random()).toBe(1); | ^ 9 | }); 10 | it("randomPlusOne", () => { 11 | expect(obj.randomPlusOne()).toBe(2); at Object.<anonymous> (sample.test.js:8:26) ● sample › randomPlusOne expect(received).toBe(expected) // Object.is equality Expected: 2 Received: 1.732370688737492 9 | }); 10 | it("randomPlusOne", () => { > 11 | expect(obj.randomPlusOne()).toBe(2); | ^ 12 | }) 13 | }) 14 | at Object.<anonymous> (sample.test.js:11:33) -----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s -----------|---------|----------|---------|---------|------------------- All files | 100 | 100 | 100 | 100 | sample.js | 100 | 100 | 100 | 100 | -----------|---------|----------|---------|---------|------------------- Test Suites: 1 failed, 1 total Tests: 2 failed, 2 total Snapshots: 0 total Time: 0.537 s, estimated 1 s
ここで、一旦モックから離れて、ロジックに全く関与していない次のようなテストを試してみる。
describe("sample", () => { it("1+1", () => { expect(1 + 1).toBe(2); }); })
予想通り、カバレッジは0%になる。
$ npm run test > jest-playground@1.0.0 test > jest --collectCoverage PASS ./sample.test.js sample ✓ 1+1 (2 ms) ----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------|---------|----------|---------|---------|------------------- All files | 0 | 0 | 0 | 0 | ----------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.526 s, estimated 1 s Ran all test suites.
次に、前回のテストにrequireだけしたテストを試してみる。
const obj = require("./sample"); describe("sample", () => { it("1+1", () => { expect(1 + 1).toBe(2); }); })
すると、ロジックに全く関与していないのにrequireしただけでカバレッジは上昇している。
$ npm run test > jest-playground@1.0.0 test > jest --collectCoverage PASS ./sample.test.js sample ✓ 1+1 (2 ms) -----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s -----------|---------|----------|---------|---------|------------------- All files | 50 | 100 | 0 | 50 | sample.js | 50 | 100 | 0 | 50 | 3-6 -----------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.433 s, estimated 1 s Ran all test suites.
次はモックを実装して試してみる。
const obj = require("./sample"); jest.spyOn(obj, 'random').mockImplementation(() => 1); jest.spyOn(obj, 'randomPlusOne').mockImplementation(() => 2); describe("sample", () => { it("random", () => { expect(obj.random()).toBe(1); }); it("randomPlusOne", () => { expect(obj.randomPlusOne()).toBe(2); }) })
カバレッジの結果は前回と同じであり、つまり、モックはカバレッジに関与していないことがわかる。
$ npm run test > jest-playground@1.0.0 test > jest --collectCoverage PASS ./sample.test.js sample ✓ random (2 ms) ✓ randomPlusOne (1 ms) -----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s -----------|---------|----------|---------|---------|------------------- All files | 50 | 100 | 0 | 50 | sample.js | 50 | 100 | 0 | 50 | 3-6 -----------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 0.571 s, estimated 1 s Ran all test suites.
次のように、JestのモックではなくSinon.JSを用いてテストしてみる。
const obj = require("./sample"); const sinon = require("sinon"); const randomStub = sinon.stub(obj, "random"); randomStub.returns(1); const randomPlusOneStub = sinon.stub(obj, "randomPlusOne"); randomPlusOneStub.returns(2); describe("sample", () => { it("random", () => { expect(obj.random()).toBe(1); }); it("randomPlusOne", () => { expect(obj.randomPlusOne()).toBe(2); }); });
カバレッジの結果は前回と同じであり、つまり、モックの方法もテストに関与していないことがわかる。
$ npm run test > jest-playground@1.0.0 test > jest --collectCoverage PASS ./sample.test.js sample ✓ random (2 ms) ✓ randomPlusOne -----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s -----------|---------|----------|---------|---------|------------------- All files | 50 | 100 | 0 | 50 | sample.js | 50 | 100 | 0 | 50 | 3-6 -----------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 0.635 s
まとめ
- モックの実装やモックの方法はカバレッジに関与していない