Skip to content

Commit

Permalink
writing
Browse files Browse the repository at this point in the history
  • Loading branch information
ken7253 committed May 13, 2024
1 parent 7fc52fa commit 409671e
Showing 1 changed file with 166 additions and 2 deletions.
168 changes: 166 additions & 2 deletions hooks-testing/slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ src: "../reuse/me.md"

### Hooks(カスタムHooks)とは

- 組み込みのHooks(`useState`/`useEffect`など)を組み合わせて作る関数
- ルールは組み込みHooksと一緒
- `use***`という命名規則を持つ
- コンポーネントもしくはHooksのトップレベルでのみ実行できる

サードパーティで有名なHooks

- [useQuery](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery)(Tanstack Query)
- [useRouter](https://nextjs-ja-translation-docs.vercel.app/docs/api-reference/next/router)(next/router)

特殊な制約を持った関数ぐらいの認識でもOK

https://ja.react.dev/reference/rules/rules-of-hooks

---

### シグニチャーとは
Expand All @@ -34,11 +48,38 @@ src: "../reuse/me.md"

これらの情報をまとめてシグニチャーという

シグニチャーが正しく、適切な情報量を持っていれば挙動が推測できる。

---
layout: center
---

## 関数の単体テストについて簡単に復習
## 関数の単体テストについて簡単に確認

---

### 単体テストはどのように書くか

例として、引数として与えられた配列を全て足し合わせる`sum`関数を考える。

```ts
export const sum = (array: number[]): number => {
if (array.some(v => v === Infinity || v === -Infinity)) {
return Infinity;
}

return array.reduce(
(a, c) => a + (Number.isNaN(c) ? c : 0), 0
);
}
```

- 基本的には配列の加算
- NaNがあった場合`0`として扱う(無視する)
- `Infinity`が含まれていた場合は常に`Infinity`を返す

この関数に対してのテストを書く

---

### 単体テストはどのように書くか
Expand Down Expand Up @@ -68,6 +109,87 @@ describe('引数として与えられた配列を全て足し合わせるsum関

---

### 単体テストはどのように書くか

よくあるのは関数に引数を渡して、返り値を検査するパターン。

```ts{4-6}
import { describe, test, expect } from "vitest";
import { sum } from "./index.ts";
describe('引数として与えられた配列を全て足し合わせるsum関数', () => {
describe('引数が全て有効な数値の場合', () => {
test('配列を足し合わせた数値が返却される', () => {
const array = [1, 2, 3, 4, 5];
const sumResult = sum(array);
expect(sumResult).toBe(15);
})
});
describe('計算不能な数値型が含まれている場合', () => {
test('NaNが含まれていた場合0として扱う', () => { /* 略 */ });
test('Infinityが含まれていた場合常にInfinityを返却する', () => { /* 略 */ });
});
});
```

---

### 単体テストはどのように書くか

よくあるのは関数に引数を渡して、返り値を検査するパターン。

```ts{4,14-15}
import { describe, test, expect } from "vitest";
import { sum } from "./index.ts";
describe('引数として与えられた配列を全て足し合わせるsum関数', () => {
describe('引数が全て有効な数値の場合', () => {
test('配列を足し合わせた数値が返却される', () => {
const array = [1, 2, 3, 4, 5];
const sumResult = sum(array);
expect(sumResult).toBe(15);
})
});
describe('計算不能な数値型が含まれている場合', () => {
test('NaNが含まれていた場合0として扱う', () => { /* 略 */ });
test('Infinityが含まれていた場合常にInfinityを返却する', () => { /* 略 */ });
});
});
```

---

### 単体テストはどのように書くか

よくあるのは関数に引数を渡して、返り値を検査するパターン。

```ts{4,14,16}
import { describe, test, expect } from "vitest";
import { sum } from "./index.ts";
describe('引数として与えられた配列を全て足し合わせるsum関数', () => {
describe('引数が全て有効な数値の場合', () => {
test('配列を足し合わせた数値が返却される', () => {
const array = [1, 2, 3, 4, 5];
const sumResult = sum(array);
expect(sumResult).toBe(15);
})
});
describe('計算不能な数値型が含まれている場合', () => {
test('NaNが含まれていた場合0として扱う', () => { /* 略 */ });
test('Infinityが含まれていた場合常にInfinityを返却する', () => { /* 略 */ });
});
});
```

---

### 単体テストと純粋関数

このとき関数自体が純粋関数ではない場合テストが書きづらい。
Expand All @@ -79,21 +201,63 @@ export const sum = (array: number[]) => {
}

const sumAll = array.reduce(
(a, c) => Number.isNaN(c) ? a + 0 : a + c, 0
(a, c) => a + (Number.isNaN(c) ? c : 0), 0
);

return sumAll * Math.random();
}
```

`Math.random()`は実行毎に値が変わってしまうのでテストしづらい。

---

### 副作用を除去してテストしやすい関数を作る

副作用は外部から渡して純粋関数にする。

```ts{1,10}
export const sum = (array: number[], randomize: number) => {
if (array.some(v => v === Infinity || v === -Infinity)) {
return Infinity;
}
const sumAll = array.reduce(
(a, c) => a + (Number.isNaN(c) ? c : 0), 0
);
return sumAll * randomize;
}
```

テストをするときは`randomize`に固定値を入れれば保証したいロジックを検査できる。

---

## 単体テストの考え方をHooksにも適用する

Hooksのテストは`testing-library`によって提供されているのでそれを使う。
例えばNext.jsの`pathname`でFizzBuzzをしたい時に利用するHooksを考える。

```ts
import { useRouter } from "next/router";

export const useFizzBuzz = () => {
const { pathname } = useRouter();
const pathNumber = parseInt(pathname, 10);

if (pathNumber % 3 === 0 && pathNumber % 5 === 0) {
return 'FizzBuzz';
} else if (pathNumber % 3 === 0) {
return 'Fizz';
} else if (pathNumber % 5 === 0) {
return 'Buzz';
} else {
return pathNumber;
}
};
```

---

### テストしづらい依存の除去
Expand Down

0 comments on commit 409671e

Please sign in to comment.