検索条件
お知らせ
現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
単体テストの観点でいうとprocess.argv
そのものはモックしないほうが良いと思っているので、本記事ではprocess.argv
自体をモックする方法と、それを回避する方法を紹介する
describe('example', () => {
afterEach(() => {
// 元に戻しておく
process.argv.length = 2;
});
it('got first param', () => {
process.argv.push('param1');
expect(process.argv.length).toBe(3);
expect(process.argv[2]).toBe('param1');
});
});
process.argv
を利用している関数でprocess.argv
を引数に取ればモック不要となる
const getArgv = (argv: string[]) => {
// some procedure
}
describe('getArgv', () => {
it('got first param', () => {
const argv = [,, 'param1'];
expect(argv.length).toBe(3);
expect(argv[2]).toBe('param1');
});
});
run
コマンドでサービスを指定してコマンドを蹴ると実行結果が取れる
- e.g.
docker-compose run node-git 'npm' 't'
- コマンドを複数繋げる場合はシェルを呼び出してやる
- e.g.
docker-compose run node-git 'sh' '-c' '"ls -la && grep foo"'
取り敢えず各ジョブの中で使うやつ
今まで使っていた::set-output
は2023-05-31に廃止される予定なので置き換える必要があります。
GitHub Actions: Deprecating save-state and set-output commands
- 設定方法:
echo "<KEY>=<VALUE>" >> "$GITHUB_OUTPUT"
- 参照方法:
steps.<ID>.outputs.{KEY}
name: variable example
on:
workflow_dispatch:
jobs:
ubuntu-testing:
runs-on: ubuntu-latest
steps:
- id: example
run: echo "value=hoge" >> "$GITHUB_OUTPUT"
- name: disp
run: echo ${{ steps.example.outputs.value }}
フックを単体でテストするケースを想定。
このパターンはコンポーネントからフックを切り離しているケースで有用。手法としては@testing-library/react-hooks
のrenderHook()
を使う。
export const useUserForm = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const onChangeUserName = (ev: string) => {
setUsername(ev);
};
const onChangePassword = (ev: string) => {
setPassword(ev);
};
return {
username,
password,
onChangeUserName,
onChangePassword,
};
};
it('onChangeUserName で username が設定されること', () => {
// `renderHook` で Hook をレンダリング
const { result } = renderHook(() => useUserForm());
// `act()` で Hook のイベントを叩く
act(() => result.current.onChangeUserName('foo'));
// 結果を見る
expect(result.current.username).toBe('foo');
});
Env |
Ver |
Node.js |
12.18.3 |
Jest |
26.4.2 |
以下の実装のときに、parentFunc()
を呼んだ時にchildFunc()
が呼ばれることをテストしたい
function parentFunc() {
console.log('called parentFunc');
childFunc('XXXX');
}
function childFunc(param) {
console.log(`called childFunc ${param}`);
}
テストするためには関数をexportする必要あるが、愚直過ぎて構文的に実行不能になるケース
exports.parentFunc = () => {
console.log('called parentFunc');
// childFuncは別モジュールなので呼べない
childFunc('XXXX');
};
exports.childFunc = (param) => {
console.log(`called childFunc ${param}`);
};
この実装を実行すると期待通り動作するので、一見すると大丈夫そうに見える
function parentFunc() {
console.log('called parentFunc');
childFunc('XXXX');
}
function childFunc(param) {
console.log(`called childFunc ${param}`);
}
module.exports = { parentFunc, childFunc };
しかしこのテストを流すと失敗する
これはparentFunc()
が呼び出すchildFunc()
が下記case2
の中にないため
parentFunc()
のスコープ内にchildFunc()
がいないことが原因
const case2 = require('./case2');
// こうするとjest.spyOn()の第一引数を満たせないので落ちる
// const { parentFunc, childFunc } = require('./case2');
describe('inside call test', function () {
it('parentFunc', function () {
const spy = jest.spyOn(case2, 'parentFunc');
case2.parentFunc();
expect(spy).toHaveBeenCalled();
});
it('childFunc', function () {
const spy = jest.spyOn(case2, 'childFunc');
case2.parentFunc();
// childFuncはcase2に属していないため呼ばれない
expect(spy).toHaveBeenCalled();
});
});
const parentFunc = () => {
console.log('called parentFunc');
// parentFunc()の中にchildオブジェクトを注入することで、
// jestがchildFunc()を認識できるようにする
child.childFunc('XXXX');
};
const child = {
childFunc: (param) => {
console.log(`called childFunc ${param}`);
},
};
// childFuncでなく、childオブジェクトをexportするのが味噌
module.exports = { parentFunc, child };
const case3 = require('./case3');
describe('inside call test', function () {
it('parentFunc', function () {
const spy = jest.spyOn(case3, 'parentFunc');
case3.parentFunc();
expect(spy).toHaveBeenCalled();
});
it('childFunc', function () {
// 注入している側のオブジェクトを参照する
const spy = jest.spyOn(case3.child, 'childFunc');
case3.parentFunc();
// child.childFuncはcase3に属しているため呼ばれる
expect(spy).toHaveBeenCalled();
});
});