From 1a3d023f4e983cb7a0cf32181a1d72c66fa4e24f Mon Sep 17 00:00:00 2001 From: ken7253 Date: Sat, 27 Sep 2025 22:49:37 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E8=A8=98=E4=BA=8B=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/implementation-for-testing.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 articles/implementation-for-testing.md diff --git a/articles/implementation-for-testing.md b/articles/implementation-for-testing.md new file mode 100644 index 0000000..c015dc0 --- /dev/null +++ b/articles/implementation-for-testing.md @@ -0,0 +1,7 @@ +--- +title: "テストのために実装を変えるという視点を持つ" +emoji: "👀" +type: "tech" # tech: 技術記事 / idea: アイデア +topics: ["test"] +published: false +--- From 207b8ef53d4734199c8f68075552e616d59b8dac Mon Sep 17 00:00:00 2001 From: ken7253 Date: Mon, 13 Oct 2025 17:21:30 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E8=A6=8B=E5=87=BA=E3=81=97=E3=82=92?= =?UTF-8?q?=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/implementation-for-testing.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/articles/implementation-for-testing.md b/articles/implementation-for-testing.md index c015dc0..c286f7d 100644 --- a/articles/implementation-for-testing.md +++ b/articles/implementation-for-testing.md @@ -5,3 +5,12 @@ type: "tech" # tech: 技術記事 / idea: アイデア topics: ["test"] published: false --- + +# テストのために実装を変えるという視点を持つ + +## テストのために実装を変えるとはなにか + +### テスト用の引数を用意する + +### 不要な引数を受け取らないようにする + From 2ccb47589cd86aaf7526072fa0199dd5a999ff40 Mon Sep 17 00:00:00 2001 From: ken7253 Date: Fri, 24 Oct 2025 14:39:47 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=E3=81=96=E3=81=A3=E3=81=8F=E3=82=8A?= =?UTF-8?q?=E6=A7=8B=E6=88=90=E3=82=92=E8=A6=8B=E7=9B=B4=E3=81=97=E3=81=A6?= =?UTF-8?q?=E6=9B=B8=E3=81=8D=E7=9B=B4=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/implementation-for-testing.md | 49 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/articles/implementation-for-testing.md b/articles/implementation-for-testing.md index c286f7d..bf4ddaa 100644 --- a/articles/implementation-for-testing.md +++ b/articles/implementation-for-testing.md @@ -1,16 +1,33 @@ ---- -title: "テストのために実装を変えるという視点を持つ" -emoji: "👀" -type: "tech" # tech: 技術記事 / idea: アイデア -topics: ["test"] -published: false ---- - -# テストのために実装を変えるという視点を持つ - -## テストのために実装を変えるとはなにか - -### テスト用の引数を用意する - -### 不要な引数を受け取らないようにする - +--- +title: "テストのために実装を変えるという視点を持つ" +emoji: "👀" +type: "tech" # tech: 技術記事 / idea: アイデア +topics: ["test"] +published: false +--- + +この記事はテストコードを書きたいと考えているが実際にどのように書けばよいかわからない人向けの記事です。 + +## なんのためにテストを書くのか + +まず始めに私達はなぜテストコードを書くのでしょうか。 + +これは極端な例ではありますが、テストコードを正しくかけていればレビュー時の動作確認不要になります。 + +## まずは関数のテストから始める + +テストコードを書く場合まずは関数の動作を確認するテストコードから書き始めるとよいです。 + +テストケースの基本は、入力に対して出力期待された値であることを確認することにあります。 + + + +## テストしやすいように実装を変えるという視点を持つ + + + +### 不要な引数を受け取らないようにする + +### テスト用の引数を用意する + +### 関数は必ず値を返すようにする From 9b6a8769c601d1c31ee2bd20605ba3f4f70310d5 Mon Sep 17 00:00:00 2001 From: ken7253 Date: Fri, 24 Oct 2025 15:08:09 +0900 Subject: [PATCH 4/5] WIP --- articles/implementation-for-testing.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/articles/implementation-for-testing.md b/articles/implementation-for-testing.md index bf4ddaa..fae0e3a 100644 --- a/articles/implementation-for-testing.md +++ b/articles/implementation-for-testing.md @@ -12,6 +12,8 @@ published: false まず始めに私達はなぜテストコードを書くのでしょうか。 +これにはいくつかの + これは極端な例ではありますが、テストコードを正しくかけていればレビュー時の動作確認不要になります。 ## まずは関数のテストから始める @@ -28,6 +30,27 @@ published: false ### 不要な引数を受け取らないようにする +よくある例として、下記のように様々な情報がまとまったUser型の値を受け取っているにもかかわらず実際に利用するのは + +```ts +type User = { + id: string; + name: string; + shortName: string; + subscribeState: { + enable: boolean; + usePromotion: boolean; + caseName: string; + point: number; + } + // ... 多くのプロパティ +}; +``` + +```ts + +``` + ### テスト用の引数を用意する ### 関数は必ず値を返すようにする From 82ee56376d26c338073233ecce359306f8e37d9e Mon Sep 17 00:00:00 2001 From: ken7253 Date: Fri, 28 Nov 2025 20:44:19 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/implementation-for-testing.md | 79 +++++++++++++++++--------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/articles/implementation-for-testing.md b/articles/implementation-for-testing.md index fae0e3a..306478f 100644 --- a/articles/implementation-for-testing.md +++ b/articles/implementation-for-testing.md @@ -6,51 +6,78 @@ topics: ["test"] published: false --- -この記事はテストコードを書きたいと考えているが実際にどのように書けばよいかわからない人向けの記事です。 +皆さんは普段どのぐらいのテストを書いていますか。 -## なんのためにテストを書くのか +## なぜテストが書けないと思うのか -まず始めに私達はなぜテストコードを書くのでしょうか。 +これは私の経験則ですがテストが書けないという人は多くの場合、テストが書きやすいように関数やモジュールを設計していないという傾向があるように感じます。 -これにはいくつかの +テストが書きずらい関数 -これは極端な例ではありますが、テストコードを正しくかけていればレビュー時の動作確認不要になります。 +### 不要な引数を多く受け取る -## まずは関数のテストから始める +これは特にフロントエンドのコンポーネント設計などで多く見られる例で、API等から受け取った巨大なオブジェクトをそのままバケツリレーしている場合などがあてはまります。 -テストコードを書く場合まずは関数の動作を確認するテストコードから書き始めるとよいです。 +例として、ユーザー情報オブジェクトとログイン情報を取り下記の仕様通りに値を返す関数を考えます。 -テストケースの基本は、入力に対して出力期待された値であることを確認することにあります。 +- ユーザーが未ログインの場合は`"ゲスト"`という文字列を返す。 +- ユーザーがログイン状態かつ、所属組織(`user.org`)が存在すれば所属組織とユーザー名をスペースで結合して返す。 +- 所属組織がない場合、ユーザー名のみを返す。 - - -## テストしやすいように実装を変えるという視点を持つ +```ts +const constructUserName = (user: User, isLogin: boolean) => { + if (!isLogin) { + return "ゲスト"; + } + if (typeof user.org === 'string' && user.org !== '') { + return `${user.org} ${user.name}`; + } - + return user.name; +} +``` -### 不要な引数を受け取らないようにする +この場合、`User`型が`user.name`と`user.org`だけの小さなオブジェクトであればテストケースを書くのは比較的楽です。 -よくある例として、下記のように様々な情報がまとまったUser型の値を受け取っているにもかかわらず実際に利用するのは +一方でこのオブジェクトが非常に複雑な構造を持つオブジェクトだったらどうでしょうか? ```ts type User = { - id: string; name: string; - shortName: string; - subscribeState: { - enable: boolean; - usePromotion: boolean; - caseName: string; - point: number; - } - // ... 多くのプロパティ -}; + org?: string; + // ... more 100 properties +} ``` +ここまで極端な例はあまりないかと思いますが、このように不要なプロパティを含めて受け取ると後からテストを書こうとしたときに非常に面倒なことになりがちです。 + +その結果テストを書く工数に対してメリットが感じられずにテストを書かないという選択肢を取りがちになります。 + +ではこの関数を最小限の情報だけ取得する関数に変えるとどうでしょうか。 + ```ts +const constructUserName = (name: string, isLogin: boolean, org?: string) => { + if (!isLogin) { + return "ゲスト"; + } + if (typeof org === 'string' && org !== '') { + return `${org} ${name}`; + } + return name; +} ``` -### テスト用の引数を用意する +上で定義されている`User`型のように不要なプロパティを定義せずとも3つの引数を渡し、パターンを網羅すればよさそうです。 + +```ts +describe('ログインしていないユーザーの場合', () => { + test('常に「ゲスト」という文字列を返却する', () => { + const name = constructUserName('ゲストではない', false); + + expect(name).toBe('ゲストではない'); + }) +}) +``` -### 関数は必ず値を返すようにする +### 副作用の分離ができていない