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
まとめ
- モックの実装やモックの方法はカバレッジに関与していない