kakakakakku blog

Weekly Tech Blog: Keep on Learning!

go test -short で長時間実行されるテストをスキップする

go test でテストを実行するときに -short オプションを付けると実行対象のテストを減らせる.

例えば,長時間実行されるテストがあった場合に毎回全体の実行を待つのではなく,一部のテストをスキップすることで時間短縮できる.開発中に素早くフィードバックを得たいような場合に使えそう❗️最近使う機会があって簡単にまとめておく📝

go help testflag でヘルプを確認すると以下のように表示された.

$ go help testflag
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.

(中略)

    -short
        Tell long-running tests to shorten their run time.
        It is off by default but set during all.bash so that installing
        the Go tree can run a sanity check but not spend time running
        exhaustive tests.

testing.Short() と組み合わせる

go test -short と実行すると testing.Short() の値が true になる.よって,長時間実行されるテストが自動的に判別されるのではなく,テストコードに以下のような実装を追加することでスキップできるようになる.スキップする場合は SkipNow() 以外に Skip()Skipf() もある.

  • func (c *T) Skip(args ...any)
  • func (c *T) SkipNow()
  • func (c *T) Skipf(format string, args ...any)
if testing.Short() {
    t.SkipNow()
}

pkg.go.dev

サンプルコード

以下のように main_test.go を書いてみた.

  • TestCase1 は毎回実行される
  • TestCase2 はスキップできる
package main

import (
    "testing"
)

func TestCase1(t *testing.T) {
    got := 1
    want := 1
    if got != want {
        t.Errorf("got %d, want %d", want, got)
    }
}

func TestCase2(t *testing.T) {
    if testing.Short() {
        t.SkipNow()
        // t.Skip("it skipped")
        // t.Skipf("it skipped because `testing.Short()` is %t", testing.Short())
    }
    got := 1
    want := 1
    if got != want {
        t.Errorf("got %d, want %d", want, got)
    }
}

実行例 1

TestCase1TestCase2 も実行された.

$ go test -v
=== RUN   TestCase1
--- PASS: TestCase1 (0.00s)
=== RUN   TestCase2
--- PASS: TestCase2 (0.00s)
PASS
ok

実行例 2: t.SkipNow()

TestCase2 はスキップされた.

$ go test -v -short
=== RUN   TestCase1
--- PASS: TestCase1 (0.00s)
=== RUN   TestCase2
--- SKIP: TestCase2 (0.00s)
PASS
ok

実行例 3: t.Skip()

TestCase2 はスキップされた.t.Skip() で指定したログも出力された.

$ go test -v -short
=== RUN   TestCase1
--- PASS: TestCase1 (0.00s)
=== RUN   TestCase2
    main_test.go:18: it skipped
--- SKIP: TestCase2 (0.00s)
PASS
ok

実行例 4: t.Skipf()

TestCase2 はスキップされた.t.Skipf() で指定したログも出力された.

$ go test -v -short
=== RUN   TestCase1
--- PASS: TestCase1 (0.00s)
=== RUN   TestCase2
    main_test.go:19: it skipped because `testing.Short()` is true
--- SKIP: TestCase2 (0.00s)
PASS
ok

Learn Go with Tests: テスト駆動開発を体験しながら Go を学ぼう

TDD(テスト駆動開発)を体験しながら Go を学べる学習コンテンツ「Learn Go with Tests」を紹介する❗️全てのコンテンツを実施してみて,非常に良かったのでまとめることにした💡

  • Go に入門できる
  • TDD のサイクル (Red / Green / Refactor) を体験できる
  • コンテンツは "35種類" もある
  • 無料で学べる
  • GitBook (GitHub) に公開されている
  • 日本語対応

英語版 📚

quii.gitbook.io

日本語版 📚

andmorefine.gitbook.io

コンテンツ一覧

なんと「35種類」もコンテンツがある❗️

Go fundamentals 🚢 21種類

  • Install Go(Go をインストールする)
  • Hello, world(Hello, World)
  • Integers(整数)
  • Iteration(反復、繰り返し)
  • Arrays and slices(配列とスライス)
  • Structs, methods & interfaces(構造体、メソッド、インターフェース)
  • Pointers & errors(ポインタとエラー)
  • Maps(マップ)
  • Dependency Injection(依存性注入)
  • Mocking(スタブ・モック)
  • Concurrency(並行性)
  • Select(選択)
  • Reflection(リフレクション)
  • Sync(同期)
  • Context(コンテキスト)
  • Intro to property based tests(プロパティベースのテスト概要)
  • Maths(数学)
  • Reading files(ファイルの読み取り)
  • Templating(テンプレート)
  • Generics(ジェネリクス)
  • Revisiting arrays and slices with generics(ジェネリクスを使用した配列とスライスの再検討)

Build an application 🚢 6種類

  • HTTP server(HTTP サーバー)
  • JSON, routing and embedding(JSON、ルーティング、埋め込み)
  • IO and sorting(IO、並び替え)
  • Command line & project structure(コマンドライン、パッケージ構造)
  • Time(時間)
  • WebSockets(ウェブソケット)

Testing fundamentals 🚢 2種類

  • Introduction to acceptance tests(受け入れテストの紹介)
  • Scaling acceptance tests(受け入れテストを拡張する)

Questions and answers 🚢 4種類

  • OS exec(OS 実行)
  • Error types(エラーの種類)
  • Context-aware Reader(コンテキスト認識リーダー)
  • Revisiting HTTP Handlers (HTTP ハンドラーの再検討)

Meta / Discussion 🚢 2種類

  • Why unit tests and how to make them work for you(ユニットテスト機能を作成する方法)
  • Anti-patterns (アンチパターン)

quii/learn-go-with-tests より引用

おすすめ理由 1

\( 'ω')/ Red! Green! Refactor!

何よりも TDD(テスト駆動開発)のサイクルを体験し,良さを実感できることが Learn Go with Tests の1番の素晴らしさだと思う.最初に期待するテストコードを書くけど,関数名がなく undefined エラーになって,コンパイルを通しつつ,期待する実装に近付けていく.そして,リファクタリングをしながら一歩一歩改善する.

実際に体験してみると「こんなに歩幅を小さく進められるんだ〜」「過剰なリファクタリングや共通化は不要なんだ〜」ということに気付ける❗️

  • テストコードを書く(落ちる : Red)
  • コンパイルを通しつつ最低限の実装をする(落ちる : Red)
  • 実装をする(通る : Green)
  • リファクタリングをする(通る : Green)

おすすめ理由 2

\( 'ω')/ Go に詳しくなれる!

TDD(テスト駆動開発)だけではなく,Go をちゃんと学べるのも良かった.特に Go fundamentals(21種類)は目次を見るとわかる通り,Hello World・スライス・マップのような基本的なトピックから始まって,依存性注入・goroutine・リフレクション・ジェネリクスのような実践的なトピックまで学べる.

他にも Build an application(6種類)では,net/http を使った API 構築や CLI 構築も体験できる.Go で API を実装するときのテスト戦略に悩むこともあると思うし,そういった参考にもなる❗️

とは言え,完全に Go 入門者だと途中から難しくなってしまうと思うので(個人差はありそうだけど),A Tour of Go ぐらいはやっておくと良さそう👍

go-tour-jp.appspot.com

おすすめ理由 3

\( 'ω')/ テスト手法に詳しくなれる!

Learn Go with Tests はテスト手法に対する理解が深まるのも良かった.Testify などは使わずにアサートを実装するし,テーブル駆動テスト (Table Driven Test) ・プロパティ駆動テスト (Property Based Test)・承認テスト (Approval Test)・モックなど,実践的に使えるテスト手法が出てくる.

今まで「テストが書きにくいからここは諦めよう...」と悩んだことがあったらきっと参考になると思う❗️

kakakakakku.hatenablog.com

日本語に関して 🇯🇵

Learn Go with Tests には日本語版 テスト駆動開発でGO言語を学びましょう がある.とても読みやすく翻訳されているし,Google 検索で候補に出てくることもあって,検索流入で本コンテンツを知る人も多いと思う.翻訳に感謝👏

しかし現時点だと,あまりメンテナンス(プルリクエストの取り込み)はされてなく,英語版 (quii/learn-go-with-tests) に対する更新の反映も止まっている.

ちなみに以下のコンテンツには日本語版がなく,今回は英語版で実施したため,ついでに翻訳も行った.Go fundamentals の4種類は既に完了してプルリクエストは出してある✅ 引き続き残りも進めていく予定だけど,もしリポジトリ運用が回ってなかったらメンテナとしてお手伝いしたく,コラボレーター権限をもらえると嬉しいなーと❗️❗️❗️

日本語版未対応のコンテンツ一覧

英語版 GitHub リポジトリ 👾

github.com

日本語版 GitHub リポジトリ 👾

github.com

まとめ

Learn Go with Tests でテスト駆動開発を体験しながら Go を学ぼう❗️

素晴らしいコンテンツでした❗️

参考 : 所要時間

GitHub のコミット履歴を確認したら「35種類」全てを実施するまでの所要時間は1ヶ月ほど(2/3 ~ 3/7まで)だった.毎日コツコツと1時間~1時間半ほど取り組んでいたため,所要時間の参考としては「30時間ぐらい」だと思う.追加で調査をしたり,誤りを直してプルリクエストを送っていた時間も含めている.コミット数は 237 だった👌

関連記事

kakakakakku.hatenablog.com

読み手を意識したテクニカルドキュメントを書くために /「エンジニアのためのドキュメントライティング」を読んだ

2023年3月に出版された「エンジニアのためのドキュメントライティング」を読んだ.原著は Docs for Developers で,翻訳を担当された @iwashi86 さんに本書を送っていただいた.ありがとうございます❗️そして出版おめでとうございます🎉

本書は今まで書いてきたテクニカルドキュメントに対して "できてなかったな〜" という気付きを与えてくれるイイ本でした📖 読みながら感じたことを大きく分類すると以下2点!印象に残ったところを中心にまとめようと思う.

  • テクニカルドキュメントの重要さを改めて認識できた👌
  • テクニカルライティングという仕事(ポジション)に興味を持った👀

目次

  • PART I「ドキュメント作成の準備」
    • CHAPTER 1 : 読み手の理解
    • CHAPTER 2 : ドキュメントの計画
  • PART Ⅱ「ドキュメントの作成」
    • CHAPTER 3 : ドキュメントのドラフト
    • CHAPTER 4 : ドキュメントの編集
    • CHAPTER 5 : サンプルコードの組み込み
    • CHAPTER 6 : ビジュアルコンテンツの追加
  • PART Ⅲ「ドキュメントの公開と運用」
    • CHAPTER 7 : ドキュメントの公開
    • CHAPTER 8 : フィードバックの収集と組み込み
    • CHAPTER 9 : ドキュメントの品質測定
    • CHAPTER 10 : ドキュメントの構成
    • CHAPTER 11 : ドキュメントの保守と非推奨化

テクニカルドキュメントをプロダクト開発のように考える

本書を読んで印象に残ったのは,ドキュメントも「プロダクト開発のように考えている」というところ.ドキュメントの読み手(ペルソナ・目的)を整理して,ドキュメントをうまく構造化してまとめて,評価やフィードバックを基に改善を繰り返す.まさにプロダクト開発のフローのように感じられたし,同時にそれほど注力するべきとも言える❗️ドキュメントライティングをある意味 "おまけのように" 考えてしまうと,価値がなく誰にも読まれないドキュメントになってしまう可能性もある.

CHAPTER 1 で解説されている「読み手の理解」は良かった👏 ドキュメントの読み手を意識してドキュメントを書くべきということは頭では理解していても案外できていないこともありそう.結果的に "独りよがりな" ドキュメントを書いてしまうことにも繋がる.そして,ドキュメントを読んでもうまく使えなかったときの状況をまとめる「フリクションログ」というテクニックも参考になった.

知識の呪い

人間は他人が自分と同じ知識を持っていると思い込んでいる という認知バイアスを「知識の呪い」として紹介されていたのも良かった.僕自身は技術講師(テクニカルトレーナー)として働いているため,技術を教える立場としてこの「知識の呪い」には絶対に該当しないように常に気を付けているけど,ドキュメントライティングでも意識するべきだと気付けた.

テクニカルドキュメントの種類

CHAPTER 2 でテクニカルドキュメントの種類(コンテンツタイプ)が以下のようにまとまっていて,分類として参考になった.ここまで厳密に分類されてドキュメントが公開されている事例ってどのぐらいあるんだろう.また "コンセプトドキュメントや手順書" は「教育や情報提供」を取り扱って,"リファレンスドキュメント" は「原因と結果」を取り扱うという解説があって,ここでも読み手を意識した分類になっているんだなぁーと感じた.

  • コードコメント
  • README
  • スタートガイド (Getting Started)
  • コンセプトドキュメント
  • 手順書
    • チュートリアル (Tutorial)
    • ハウツーガイド (How To Guide)
  • リファレンスドキュメント
    • API リファレンス
    • 用語集
    • トラブルシューティングドキュメント
    • 変更に関するドキュメント (Change Log)

そして,僕は気になるサービスやツールを試すときに「チュートリアル」を試してテックブログにまとめることが多く,チュートリアルの良し悪しによってそのサービスやツールへの第一印象が決まってしまう.実際にこういう体験があるからこそ,テクニカルドキュメントの重要性も改めて認識できた.また本書では Getting Started / Tutorial / How To Guide それぞれの違いがまとまっていたのも良かった.Getting Started = Tutorial というドキュメントも結構ある気がする...

非推奨化 (deprecated)

ドキュメントは1度書いて終わりではなく継続的にメンテナンスをしていく必要がある.メンテナンス計画を考えたり,ドキュメントオーナーを任命するなど,CHAPTER 11 で解説されている内容は特に良かった.またメンテナンス作業をできる限り自動化するというプラクティスも参考になった.

  • 鮮度確認(最終更新日を表示する)
  • リンクチェッカー(リンク切れを回避する)
  • ドキュメントリンター(文章チェックをする)
  • リファレンスドキュメント生成(OpenAPI / Swagger などを活用した自動化)

ドキュメントリンターとして textlint は便利だし,textlint-rule-no-dead-link を使えば textlint でリンク切れも検知できる.

kakakakakku.hatenablog.com

そして,不要になったドキュメントを突然消すのではなく,非推奨化 (deprecated) という形で事前に読み手に伝えるというプラクティスも実体験としてあると嬉しく,明確にまとまっていて良かった.実は CHAPTER 11 を読んでいて "書いてあったら引用しやすくて嬉しいなぁー" と思っていたことがあって,それは「ドキュメントを削除するときに最低限リダイレクト設定はして欲しい」という話なんだけど,最後の "まとめ"ユーザーが立ち往生しなくて済むようにリダイレクトを設定してください。 と書いてあって「最高〜」と心の中で叫んだw

テックブログに当てはめて考える

本書で取り扱う "テクニカルドキュメント" として,テックブログは当てはまらないところもあるとは思うけど,テックブロガーとして参考になるプラクティスもあった.例えば,CHAPTER 5 で解説されているサンプルコードのプラクティスや CHAPTER 6 で解説されている図解の必要性(百聞は一見にしかず)など❗️

さらに CHAPTER 3 で解説されていた「流し読みに適した書き方」というのは重要なマインドセットだと思った.テックブログを書いてる側としてはうまく推敲した文章全てを上から下まで読んでもらいたいとは思うけど,実際には "知りたいことを最速で見つけたい" というニーズも多いはずで,期待した通りに読まれないことを受け入れる必要がある.TL;DR を活用したり,文章を簡潔にまとめたり,図解を活用したり,今後工夫できることはたくさんあるな〜と気付けた💡

\( 'ω')/ 流し読み時代を受け入れよう!

付録 B(リソース)と付録 C(参考文献)

本書では関連するウェブサイトや論文など,多くの引用元が注釈されていて,さらに本書の最後には付録としてまとまっていた.付録は非常にありがたく,はじめて出会えたものもあれば,読もう読もうと思って後回しにしていたものもあって,優先順位を上げるきっかけになった❗️

Google 提供の Technical Writing Courses は前から気になっていたけどまだ受講できてなく,やるぞー!という気持ちになった.本書には2コースと書かれていたけど,現在は4コースありそう.

  • Technical Writing One
  • Technical Writing Two
  • Tech Writing for Accessibility
  • Writing Helpful Error Messages

developers.google.com

REST API のドキュメント開発を学べるコース💡内容的には非常に深く気になるけど,162ページもあってボリュームすげぇーw

  • I: Introduction to REST APIs
  • II: Using an API like a developer
  • III: Documenting API endpoints
  • IV: OpenAPI spec and generated reference docs
  • V: Step-by-step OpenAPI code tutorial
  • VI: Testing API docs
  • VII: Conceptual topics in API docs
  • VIII: Code tutorials
  • IX: The writing process
  • X: Publishing API docs
  • XI: Thriving in the API doc space
  • XII: Native library APIs
  • XIII: Processes and methodology
  • XIV: Metrics and measurement
  • XV: Additional resources

idratherbewriting.com

ソフトウェアアーキテクチャをうまく表現するための C4 model (context, containers, components, code) も理解しておこう.

c4model.com

その他メモ

  • エラーをドキュメントに載せるときは検索しやすいように1ページにまとめる
  • コールアウト
  • 完璧主義 から脱却する(書籍 "完璧を求める心理" とも関係しそう)
  • プラッシング (Plussing)
  • サンプルコードを動かすサンドボックス環境があると便利だけど多くの場合は過剰
  • テクニカルライターの多くはメンテナンスの面から映像には慎重
  • TTHW (Time to Hello World)

kakakakakku.hatenablog.com

あわせて読みたい・聞きたい

本書のポイントや本書とあわせて読むと良さそうな名著「理科系の作文技術」などの紹介もあって非常にうまくまとめられていた.実は本書を読みながら,対象としているテクニカルドキュメントの具体的なイメージが掴めず,数回戻って読み直したりしていた.最終的に SaaS / OSS ドキュメント・API ドキュメント・GitHub の README.md などを想像しながら読むことにしたけど,社内ドキュメントはどうなんだろう〜?という点は疑問だった.以下のスライドの P.50-51 でちゃんと 実際にはほとんどのドキュメントで応用可能 とフォローアップされていた❗️

speakerdeck.com

原著の共著者 Zachary Sarah Corleissen にインタビューする fukabori.fm のエピソードも良かった📻

fukabori.fm

まとめ

2023年3月に出版された「エンジニアのためのドキュメントライティング」を読んだ.重要なのは本書で学んだプラクティスを実践して,ドキュメントによって読み手を支援できるかどうかだと思う.できそうなところから着手していこう.また今まで長年テックブログを書き続けているけど,この経験を役立てられそうなテクニカルライティングという仕事(ポジション)にも興味を持った💡

テクニカルドキュメントの重要さを改めて認識できるイイ本でした❗️おすすめ❗️

誤植など

既に報告されているかもしれないけど 初版第一刷 を読んでいて気付いたところをまとめておくー👾

  • P.42 表してします。表しています。
  • P.54 コンセプトガイドコンセプトドキュメント(もしかしたら表記揺れ?)
  • P.59 熱心の熱心な
  • P.84 アップロートアップロード
  • P.211 KubenetesKubernetes
  • P.222 付録 2付録 B
  • P.228 https://snagit.com/https://www.techsmith.com/screen-capture.html(リダイレクトされる?)

関連記事

kakakakakku.hatenablog.com

go-approval-tests: Go で「承認テスト」を実装する

Approval Tests というツールセットを使うと簡単に「Approval Testing(承認テスト)」を実装できる.Approval Testing では,スナップショットテストのように "結果全体を意識した" テストコードを記述する.GitHub には Golden master Verification Library とも書かれていて,BDD (Behavior-Driven Development) で使われることもある.

単体テストを実装するときに一般的に使われる assertEquals のようなアサーションだと値ごとに細かく検証することになるため,ファイル全体やオブジェクト内容を検証するときの選択肢になる.今回紹介する Approval Tests は多くのプログラミング言語をサポートしている💡

approvaltests.com

最近 Go で go-approval-tests (ApprovalTests.go) を使う機会があって,学んだことを簡単にまとめておくことにした❗️ドキュメントを確認すると多くの Verify 関数が実装されている.以下に代表的なものを載せておく📝他にもまだまだある〜

  • VerifyString()
  • VerifyMap()
  • VerifyJSONBytes()
  • VerifyJSONStruct()
  • VerifyAllCombinationsFor1()
  • VerifyAllCombinationsFor2()

github.com

pkg.go.dev

approvals/ApprovalTests.Go.StarterProject リポジトリ

今回は動作確認に使える Starter Project(サンプルプロジェクト)を使って go-approval-tests を試す.まず sample.gosample_test.go を載せておく❗️

github.com

sample.go

  • Person 構造体
package starterpackage

type Person struct {
    Name string
    Age  int
}

sample_test.go

  • TestNormalTest() テスト(一般的な値比較)
  • TestBasicApproval() テスト(go-approval-tests で文字列比較)
  • TestJsonApproval() テスト(go-approval-tests で JSON 比較)
  • TestCombinationsApproval() テスト(go-approval-tests で組み合わせ比較)
package starterpackage

import (
    "fmt"
    approvals "github.com/approvals/go-approval-tests"
    "testing"
)

func TestNormalTest(t *testing.T) {
    if 5 != 5 {
        t.Fatal("5 != 5")
    }
}

func TestBasicApproval(t *testing.T) {
    approvals.VerifyString(t, "Hello Approvals")
}

func TestJsonApproval(t *testing.T) {
    person := Person{
        "John Galt", 100,
    }
    approvals.VerifyJSONStruct(t, person)
}

func TestCombinationsApproval(t *testing.T) {
    arr := []int{10, 20, 30, 40}
    names := []string{"john", "paul", "mary"}
    approvals.VerifyAllCombinationsFor2(t, "File Names", func(a interface{}, b interface{}) string { return fmt.Sprintf("%v_%v.txt", a, b) }, names, arr)
}

VerifyString() 関数

まず VerifyString() 関数を確認する.以下のコードでは Hello Approvals という文字列が返ってくる場合(正確にはビジネスロジックから得られた値)をテストしている.go-approval-tests では「期待値」はファイルに記載する.

func TestBasicApproval(t *testing.T) {
    approvals.VerifyString(t, "Hello Approvals")
}

このままテストを実行すると,自動的に以下の2ファイルが作られる.received.txt には戻り値(いわゆる got)が設定されていて,approved.txt には期待値(いわゆる expected)をこれから設定する.

  • sample_test.TestBasicApproval.received.txt
  • sample_test.TestBasicApproval.approved.txt

そこで approved.txt に期待値として Hello Approvals を設定して再実行するとテストが通って,received.txt は自動的に削除される.なお,macOS で go-approval-tests を実行すると,デフォルトでは Xcode の FileMerge を使って GUI で差分を確認できる.今回の例だと文字列が短いけど,もっと長かったりすると差分を明確に確認できて便利❗️

次に戻り値を Hello Approvals ではなく Bye Approvals のように意図的に間違えて再実行すると,以下のように「どのような差分があるのか」を確認できる.

VerifyJSONStruct() 関数

go-approval-tests の GitHub に以下のように書かれている通り,単純な文字列よりも複雑なオブジェクトなどをテストするときにメリットが出てくると思う.

ApprovalTests allows for easy testing of larger objects, strings and anything else that can be saved to a file (images, sounds, csv, etc...)

VerifyJSONStruct() 関数や VerifyJSONBytes() 関数を使うと JSON オブジェクトをテストできて,サンプルコードでは VerifyJSONStruct() 関数を使って Go の struct(構造体)をテストしている.

func TestJsonApproval(t *testing.T) {
    person := Person{
        "John Galt", 100,
    }
    approvals.VerifyJSONStruct(t, person)
}

実行すると,自動的に以下の2ファイルが作られる.

  • sample_test.TestJsonApproval.received.json
  • sample_test.TestJsonApproval.approved.json

approved.txt に期待値として以下の JSON(Person 構造体に値を設定して JSON 化した)を設定してテストを再実行するとテストが通る❗️

{
  "Name": "John Galt",
  "Age": 100
}

次に戻り値の Age 「意図的に 1000 にして再実行すると,以下のように差分を確認できる.

VerifyAllCombinationsFor2() 関数

VerifyAllCombinations ではオブジェクト(コレクション)の組み合わせを検証できる.引数に与えるコレクション数によって VerifyAllCombinationsFor1() から VerifyAllCombinationsFor9() まである.サンプルコードでは VerifyAllCombinationsFor2() 関数が使われていて,id と name の配列を組み合わせて "ファイル名" を生成するロジックの検証に go-approval-tests を使っている.

func TestCombinationsApproval(t *testing.T) {
    arr := []int{10, 20, 30, 40}
    names := []string{"john", "paul", "mary"}
    approvals.VerifyAllCombinationsFor2(t, "File Names", func(a interface{}, b interface{}) string { return fmt.Sprintf("%v_%v.txt", a, b) }, names, arr)
}

流れは同じで,実行すると,自動的に以下の2ファイルが作られる.

  • sample_test.TestCombinationsApproval.received.txt
  • sample_test.TestCombinationsApproval.approved.txt

approved.txt に以下のような期待値(記述は received.txt をコピーすれば OK)を設定してテストを再実行するとテストが通る❗️

File Names


[john,10] => john_10.txt
[john,20] => john_20.txt
[john,30] => john_30.txt
[john,40] => john_40.txt
[paul,10] => paul_10.txt
[paul,20] => paul_20.txt
[paul,30] => paul_30.txt
[paul,40] => paul_40.txt
[mary,10] => mary_10.txt
[mary,20] => mary_20.txt
[mary,30] => mary_30.txt
[mary,40] => mary_40.txt

⛏️ UseFolder() 関数

デフォルトだと received.txtapproved.txt はテストコードと同じディレクトリ階層に並ぶ.テストコードが増えるほどファイルが増えて気になるようになると思う.そのときは UseFolder() 関数を使って,特定のディレクトリにファイルをまとめられる.設定する場合は Go testing を実行するときのエントリーポイントになる TestMain に以下のように実装する.

func TestMain(m *testing.M) {
    approvals.UseFolder("testdata")
    os.Exit(m.Run())
}

⛏️ UseReporter() 関数

macOS のデフォルトだと,差分確認には Xcode の FileMerge が使われる.UseReporter() 関数を使うと任意のツールに変更できる.サポートされているツールは以下など.

  • VS Code (Visual Studio Code)
  • IntelliJ
  • GoLand
  • diff コマンド

例えば VS Code を使う場合は以下のように実装する.UseFolder() 関数と組み合わせて TestMain に実装できる.

func TestMain(m *testing.M) {
    r := approvals.UseReporter(reporters.NewVSCodeReporter())
    defer r.Close()
    approvals.UseFolder("testdata")
    os.Exit(m.Run())
}

実行すると以下のように VS Code で差分を確認できた.

もし GitHub Actions など CI/CD パイプラインの実行中に差分が出てしまうこともあると思う.その場合は単純に diff コマンドを使った差分として NewRealDiffReporter() 関数も使える.env 環境変数などによって挙動を切り替えておくと良さそう.

func TestMain(m *testing.M) {
    r := approvals.UseReporter(reporters.NewRealDiffReporter())
    defer r.Close()
    approvals.UseFolder("testdata")
    os.Exit(m.Run())
}

実行すると,以下のようにテキストで差分を確認できた.real_diff_reporter.go で実装を確認したところ exec.Command("diff", "-u", approved, received) のようになっていた.

--- testdata/sample_test.TestJsonApproval.approved.json  2023-03-03 15:50:00
+++ testdata/sample_test.TestJsonApproval.received.json   2023-03-03 16:00:00
@@ -1,4 +1,4 @@
 {
   "Name": "John Galt",
-  "Age": 100
+  "Age": 1000
 }

「TOEIC 公式アプリ」を使って3ヶ月間シャドーイングを続けてみた

今回は 2022年12月〜2023年2月中旬(第2期 : 約3ヶ月間)のシャドーイングを振り返りつつ,課題と今後(既に着手している第3期)についてまとめようと思う❗️あくまで個人的な英語学習ログだから参考にはならないと思う.ちなみに英語学習の一つとしてシャドーイングに入門した 2022年8月末〜2022年11月(第1期 : 約3ヶ月間)の振り返り記事は以下にまとめてある.

kakakakakku.hatenablog.com

使ったシャドーイング教材

前回の振り返り記事の最後にも載せた通り,今回シャドーイング教材としては「TOEIC 公式アプリ (TOEIC presents English Upgrader)」を使った.「タニケイ式」のおすすめ教材にも載っていて,会話も2-3分と長くなく,レベル的にもちょうど良いと思った.また TOEIC を受験する予定もあったため,単語や表現の観点でも相乗効果が期待できそうだった.

www.iibc-global.org

まず TOEIC presents English Upgrader の良いところはエピソードの多さで,現時点だと「63種類」もある❗️

  • 1st Series(全12エピソード)
  • 2nd Series(全15エピソード)
  • 3rd Series(全20エピソード)
  • 4th Series(全7エピソード)
  • 5th Series(全9エピソード)

今回の3ヶ月間では 1st Series2nd Series「計27エピソード」を使った📻仕事的に FTPクラウドコンピューティング のエピソードに興味がありすぎたけど順番に進めたw

  • 1st Series
    1. 同僚からの留守電を聞く
    2. CD ショップでの会話
    3. クライアントへのプレゼン
    4. 電話で修理の依頼
    5. サプライズパーティーの計画
    6. FTP の説明
    7. 出産を控えた同僚との会話
    8. レポートの内容を上司に報告
    9. 電器店での会話
    10. 注文内容の確認と手配
    11. 受付での会話
    12. 新プロジェクトについての説明
  • 2nd Series
    1. 外国人社員とランチに行く
    2. クラウドコンピューティングについての説明
    3. 音声ガイドを聞く
    4. クライアントに商品の説明をする
    5. インタビュー(NHK キャサリンさん)
    6. 2010年の印象に残った出来事
    7. 英語学習アドバイス
    8. 空港でのトラブル
    9. バレンタイン
    10. クレームの電話
    11. ジョブインタビュー(海外の企業に就職する)
    12. 引越しの手配
    13. 商談で失礼に聞こえる英語
    14. パーティーの企画
    15. インタビュー(ピーター・バラカンさん1)

アプリ紹介

基本的にアプリはシンプルだから使えばわかる❗️という感じだけど,簡単にまとめておく.後ほどまとめる「シャドーイングでの使い方」「アプリの改善要望」にも繋がる.

まず,一覧からエピソードを選ぶと「リスニングモード」「クイズモード」の2種類がある

それぞれ以下のような構成になっている.

リスニングモード

  • リスニング(英語)
  • 解説(日本語)
  • リスニング(日本語)

クイズモード

  • リスニング(英語)
  • 理解度クイズ
  • 単語クイズ

スケジュール

前回の3ヶ月間では「タニケイ式」のモデルに沿って "1週間 / 1コンテンツ" で進めたけど,今回はタニケイ式のステップを流用しつつ,"3日間 / 1コンテンツ" で進めた❗️

  • Step 1. リスニング(スクリプトを見ずに音声を聞く)
  • Step 2. ディクテーション(音声を聞きながら文章を書き出す)
  • Step 3. 黙読理解(英文を理解する)
  • Step 4. 音読(速音読/中速音読/普通音読と3回読む)
  • Step 5. リピーティング(1文ずつ真似して繰り返す)
  • Step 6. オーバーラッピング(音声と同時に喋る)
  • Step 7. シャドーイング(音声の後を追いかけながら喋る)

3日間とステップの対応表は以下の通り📅

- Step 1 Step 2 Step 3 Step 4 Step 5 Step 6 Step 7
1日目
2,3日目

どんなに忙しくても毎日 "15分から1時間程度" は捻出できるように習慣化を強く意識していた.実際にやったことがあると伝わるはずだけど,特に「ディクテーション」は時間がかかってしまうため(完璧に聞き取れていない証拠でもあるけど💦),特にどのコンテンツでも「1日目」の負荷が高かった.3ヶ月間1度も止めることなくシャドーイングを継続できたことは自分を褒めたいとは思うけど,やはり仕事をしながらの時間捻出は常に課題だった.

TOEIC 公式アプリを使ったシャドーイング

ここからは,TOEIC 公式アプリを使って僕自身がどのようにシャドーイングをしたのかをまとめたいと思う.全然ベストプラクティスではないと思ってて,あくまでこうすると良いんじゃないだろうか?という仮説を基にやってみた.

✅ Step 1. リスニング

まず「Step 1. リスニング」では,「クイズモード」を使った.基本は1回で聞き取るようにして,どうしても無理だったら2,3回は聞くこともあった.そのままクイズに進んで,どのぐらい理解できているのかを確認した.TOEIC のリスニング対策にもなる.

✅ Step 2. ディクテーション

そこからまた「クイズモード」を開き直して,今度は「Step 2. ディクテーション」として紙に書き出す.エピソードによって聞き取れるものもあれば,全然聞き取れなくて落ち込むこともあった.これ以上は無理!となったらスクリプトを見ながら答え合わせをしていく.雰囲気が伝わればと思ってディクテーションをした結果を撮影してみた❗️驚くほどディクテーションできてないじゃん〜という気持ちになる.文字色は完璧ではないけど,大体以下のようにしている.

  • 黒字(ディクテーション)
  • 赤字(直し)
  • 青字(覚える単語や表現)
  • 緑字(リンキングなど発音)
  • 蛍光ペン(すぐ使えそうなフレーズなど)

✅ Step 3. 黙読理解

今度は「リスニングモード」に切り替えて「Step 3. 黙読理解」をする.黙読ではないけど,リスニングモードには日本語の解説があって,黙読理解の質を高めるために本当にイイ👏

Step 4. 音読 と Step 5. リピーティング

今度は「クイズモード」のスクリプトを使って「Step 4. 音読」を進める.ここはタニケイ式に沿って3回行う.その中で特に言いにくかったり,舌が回らないようなところは「Step 5. リピーティング」で部分的に繰り返す感じ.課題は後述するけど,1日目は「Step 2. ディクテーション」「Step 4. 音読」に時間がかかるため,「Step 5. リピーティング」はせずに諦めてしまうことも多かったのは反省点かなぁ...

✅ Step 6. オーバーラッピング と Step 7. シャドーイング

同じく「クイズモード」を使って「Step 6. オーバーラッピング」「Step 7. シャドーイング」をする.音読を毎日することで,特に3日目にはそれなりにうまくシャドーイングできたりもする(当然全然できない苦手意識のあるエピソードもいくつかあった).

振り返り

1. 楽しめた 🙆‍♂️

まず,楽しめたのは良かったと思う.TOEIC 公式アプリはエピソードのシチュエーションも多く,飽きずに楽しく続けられた.また "解説" や "クイズ" もあって,シャドーイング以外に語彙やフレーズを学べたのも良かった.前述した TOEIC 公式アプリを使ったシャドーイングはそこそこうまく機能していたと思う.

2. 習慣化できた 🙆‍♂️

前回も含めると,時間こそ短いものの「6ヶ月続けられた」ことは良かったと思う.今まで幾度となく英語学習は習慣化できず挫折してきた経緯もあり,楽しめているのは理由の1つだと思う.

3. そこまで上達してなさそう 🙅‍♂️

そもそも毎日 "15分から1時間程度" しか捻出してないなら上達するわけない!というのは理解しているし,他人と比較する必要もないとは思うけど,英語系 YouTube を見ると「たった30日で〜」とか「90日続けたら見違えるほど〜」というシャドーイング関連の動画も多く,僕自身はそういう成長曲線では進めていないなぁーと落ち込むことは多かった.それでも,英語ミーティングで少しはうまく話せたかなぁ〜という成功体験があったり,過去のエピソードのシャドーイング部分を改めてやり直すとうまく言えたりして,一歩一歩ではあるけど前進できている可能性もありそう👏あと2022年12月と2023年1月に申し込んで,特に対策はせずそのまま受験してみたけど,リスニングで "360点〜400点" ぐらいだったので,シャドーイングの効果が出ているのかも❓(ちゃんと対策する時間も捻出したいところ...)

4. 作業になりがち 🙅‍♂️

習慣化できたとは言え,ふと「作業感」を感じることも多かった.具体的には,シチュエーションを意識せずに淡々と音読をしてしまったり,シャドーイングでもロールプレイのような気持ちを持たず,ただ耳に入ってきた音を繰り返しているだけだったり.時間捻出に余裕がないからということにも関係するけど,"作業" になりがちなのは反省点の一つだとは思う.

今後どうするか

振り返りをした後にウェブや YouTube でシャドーイングの効果的なやり方などの解説を調べて「意味のないシャドーイング」に該当することが多くて刺さった🔪改善策も含めてザッとまとめると以下❗️

黙読理解を深める

シャドーイング関連の YouTube の解説でよく出てきた「文章の意味と音をリンクさせる」という点があまりできていないと思った.文章を何となく理解できたら音読に進んでしまっていて,曖昧に終わらせてしまっていた.

発音をもっと意識する

リンキングなども含めて聞こえる音を意識してシャドーイングをしてるつもりではあったけど,今後は発音記号も確認するなど,より音を意識したいと思った.

www.youtube.com

またシャドーイング以外にも発音矯正をしたいと思って,2023年2月から ELSA Speak を契約して毎日少しずつ練習をしている.ちなみに2017年頃には DMM 英会話を使っていた時期もあったけど,人と話すのは気が重く,さらにこれ以上時間を捻出できなさそうという懸念もあった.

elsaspeak.com

今後使うコンテンツは少し悩んだ.TOEIC 公式アプリを使ったシャドーイングは気に入っているし,継続したい気持ちもあったけど,もっと1回1回のクオリティを高めようとすると,どうしてもコンテンツ量が多く感じた.また ELSA Speak を毎日やるという新しい習慣も追加したため,時間捻出の面でさらに厳しくなりそうだった.そこで,YouTube などでも紹介されていた「TOEIC 公式問題集のリスニング (Part 1,2,3,4)」を使ったシャドーイングを始めることにした.実際に今は「公式 TOEIC Listening & Reading 問題集 9」を使ってもう2週間ほど続けている❗️また3ヶ月ほどたったら振り返りをしたいと思う.

公式TOEIC Listening & Reading 問題集 9

公式TOEIC Listening & Reading 問題集 9

  • 作者:ETS
  • 国際ビジネスコミュニケーション協会
Amazon

TOEIC 公式アプリ (TOEIC presents English Upgrader) の改善要望

コンテンツとしては非常に良いとは思うけど,アプリの機能面(実装面)では残念なところが多くあって困った.ちなみに環境としては Pixel 6 (Android 16) を使っている.改善要望的なことを以下に挙げておこうと思う.

  • リスニングモードで再生中に一覧に戻ると音声が再生されたままになってしまう
  • クイズモードで Android の戻るボタンを押すとリスニングモードに飛ばされて音声が二重に聞こえてしまう
    • 戻るボタンの実装が悪そう
  • バックグラウンド再生はできると書いてあるけど止まってしまうことがある
  • "10秒戻す" のような機能がなくディクテーションがしにくい
  • クイズモードの音声データが入ってなくてエラーになってしまう箇所がそこそこある

まとめ

引き続き頑張るぞ〜💪