Skip to main content
  1. Entry/

Zed から Go のテストを実行するためのカスタム Task 定義

ここ半年ほど、メインのエディタとしてZedを使っている。 動作が軽快で、生成AI関連の機能も標準でサポートされているなど、使い勝手が良いので気に入っている。

しかし、まだまだ発展途上ということもあり、乗り換え前に使っていたVSCodeと比べると、 どうしても機能的に足りない部分があるのは否めない。

足りないものの一つとして、テスト実行とそのレポート機能が挙げられる。 今回は、これを Zed の Task 定義によって補おうという話。

VSCodeのテスト実行機能 #

VSCode上でテストを実行すると、テストケースごとに成功・失敗が表示され、 各ケースの出力を個別に表示したり失敗したテストコードにジャンプしたりすることができる1

VSCode上のテスト実行結果表示。整理されて表示されるので見やすい。

一方、Zed にはいまのところテストレポートを表示する機能はない2

Task 実行機能を使えばシンプルな go test であれば実行できる。 cmd-shift-r (task: spawn) でカーソル行が含まれるテスト関数を対象に実行するメニューが表示される。

デフォルトの Task 一覧。モードに合わせて適切なものが表示される。

これはこれで便利だが、素の go test なので少々出力が見づらい。

いつもの go test の表示ではある。が、VSCode に比べると見づらさがあるのは否めない。
これをある程度解消するために、Zedに定義しているGoのテスト実行用Taskを紹介する。

Zed のカスタム Task 定義 #

Zed から実行できるTaskには、カスタム定義を加えることができる。

定義はJSONフォーマット。 ~/.config/zed/tasks.json に配置すればグローバルに、 .zed/tasks.json に配置すればプロジェクト固有の Task を定義することができる。

今回はこれを使ってGo用のテスト実行 Task を定義する。

Go 用の Task を定義する #

  • Zedが定義する変数を利用してTaskを定義
  • キーバインドを定義

Task 定義中では、Zedが用意した変数を参照することができる。 今回はそれらの変数のうち以下の2つを利用する。

変数名 用途
ZED_SYMBOL エディタカーソル直前にあるシンボル名
ZED_DIRNAME エディタで開いているファイルが配置されたディレクトリの絶対パス

Task の定義は以下のようになる。

// ~/.config/zed/tasks.json
[
  {
    "label": "Run Go Test: ${ZED_SYMBOL}",
    "command": "gotestsum --format testname -- ${ZED_DIRNAME} -run ${ZED_SYMBOL}"
  }
]

テスト結果の表示を見やすくするために、gotestsumを使う。 引数として ZED_DIRNAMEZED_SYMBOL を渡せば、エディタ中のカーソルが含まれるテストを実行することができる。

cmd-shift-r (task: spawn)を実行すると、定義した Task が表示されるようになった。 ZED_SYMBOL も展開されている。
定義した Task の実行結果。だいぶ見やすくなった。

注意点としては、 ZED_SYMBOL で必ずしもテスト関数を参照できるわけではないということ。 例えば、 struct 定義内にカーソルがあると、そこに定義されているメンバー名が参照されてしまう。 TableDrivenTests方式でテストコードを記述している場合、 テスト関数内で struct を定義することになり、これが引っかかる。

func TestFoo(t *testing.T) {
	specs := []struct {
		name string // この行にカーソルがある場合
		age  int
	}{
			...
	}

	for _, s := range specs {
		t.Run(...)
	}
}

上記コードの name 部分にカーソルがある状態でタスクを実行しようとすると、ZED_SYMBOL の値は name になってしまう。

structのメンバー名が ZED_SYMBOL として参照される。
当然意図したテストは実行されない。

とはいえ、普段コードを書きながらテストを回している中で煩わしさを感じることはほぼない。 たいていはテストケースの struct 定義部分ではなく、各テストケースを定義する部分を編集しているので。

更にキーバインドを定義してより使いやすくする。

Task を実行するためのキーバインドを定義する #

VSCode に倣って、以下のようにキーバインドを定義した。 cmd-; c でテストを実行。 cmd-; l で前回実行した Task を再実行する。

// ~/.config/zed/keymap.json
[
  {
    "context": "Editor",
    "bindings": {
      "cmd-; c": "editor::SpawnNearestTask",
      "cmd-; l": "task::Rerun",
      ...
    }
  },
  {
    "context": "Editor && (extension == go)",
    "bindings": {
      "cmd-; c": ["task::Spawn", { "task_name": "Run Go Test: ${ZED_SYMBOL}" }]
    }
  },
  ...
]

Go 以外のモードでは最も対象が近い Task を実行する editor::SpawnNearestTask を、 Go モードでは今回定義したタスクを実行するようにしている3

task::Rerun も定義することで、テストコードから離れた場所にカーソルがあっても、 即座に前回のテストを再実行することができる。

まとめ #

カスタム Task とそれを実行するキーバインドを定義することで、 Go 用のテスト実行環境をある程度満足できるレベルで整えることができた。 それでもやはりテストレポートからテストコードにジャンプする機能などは実現できていないので、今後の Zed の開発に期待したい。

Zed はほぼ毎日アップデートがあり、最近では git 操作機能4のプレビューも行われている。 活発に開発されていることが実感できるので期待が持てる。


  1. Issueはあるので気になる人は 👍 しておこう https://github.com/zed-industries/zed/issues/5242 ↩︎

  2. 詳しくは https://code.visualstudio.com/docs/editor/testing を参照。 ↩︎

  3. モードなど、エディタの状態ごとにキーバインドを定義する方法は https://zed.dev/docs/key-bindings を参照。 debug: Open Key Context View でコンテキスト確認画面を開けば、どのような context 条件を設定すればいいのかを調べることができる。 ↩︎

  4. https://zed.dev/git ↩︎