💻

GitHub Copilot で効率よくユニットテストが書ける

2023/04/01に公開

はじめに

先日マイクロソフト品川本社で行われた、GitHub MeetUp 東京 に行ってきました。
https://resources.github.com/github-meetup-tokyo/

そのイベントでは、 GitHub Copilot や GitHub Codespaces を組み合わせることで、より快適で生産的な開発環境を構築できるというプレゼンテーションが行われました。

自分はそれまでどちらも使用していなかったのですが、会場に来ていたほとんどの方が GitHub Copilot を使用していることを知り、急いでキャッチアップしました。

そこで今回は、キャッチアップした内容をもとに、 GitHub Copilot によって、ユニットテストを効率よく実装できることを紹介します。

GitHub Copilot とは?

GitHub Copilot とは、 OpenAI が開発した人工知能モデル「OpenAI Codex」を使用し、コードや機能をサジェストしてくれる "あなたのAIペアプログラマー" です。

Your AI pair programmer

GitHub Copilot uses the OpenAI Codex to suggest code and entire functions in real-time, right from your editor.

引用元: https://github.com/features/copilot

さらに GitHub は、2023年3月22日に「GitHub Copilot X」を発表しました。

https://github.com/features/preview/copilot-x

チャットや音声といったインターフェースからでもサポートを可能にするとのことです。
さらに言語やフレームワークに限らず、組織のドキュメントなどに関する質問に対しても、答えてくれるような機能も提供するとのことです。

どうやって使うのか?

自身のアカウントで GitHub Copilot を有効にする

公式ドキュメントに沿って、自身のアカウントで GitHub Copilot を有効にします。

https://docs.github.com/en/copilot/quickstart

GitHub Copilot は有料のサービスですが、2023年4月現在2ヶ月間のフリートライアルがあります。
有名なリポジトリのメンテナーなどであれば、それ以降も無償で使用できるようですね。

GitHub Copilot is free to use for verified students, teachers, and maintainers of popular open source projects. If you are not a student, teacher, or maintainer of a popular open source project, you can try GitHub Copilot for free with a one-time 60-day trial. After the free trial, you will need a paid subscription for continued use. For more information, see "About billing for GitHub Copilot."

引用元: https://docs.github.com/en/copilot/quickstart

エディタにプラグインを導入する

GitHub が複数のエディタに対応したプラグインを提供しています。
2023年4月現在は、以下のエディタに対応したプラグインが提供されています。

  • JetBrains IDEs
  • Neovim
  • Visual Studio
  • Visual Studio Code

公式ドキュメントに沿って、プラグインをエディタに導入します。
導入方法からセットアップ方法まで書かれています。

https://docs.github.com/ja/copilot/getting-started-with-github-copilot

実際にユニットテストを書いてみる

では、実際に GitHub Copilot を使用して、ユニットテストを書いてみます。
今回は Ruby と JavaScript で簡単なコードを書いて、それに対するテストコードを実装してみます。

Minitest( Ruby )

まずは以下のようなコードを実装します。

user.rb
class User < ApplicationRecord
  def generation_text
    case age
    when 10..19
      '10代'
    when 20..29
      '20代'
    when 30..39
      '30代'
    when 40..49
      '40代'
    when 50..59
      '50代'
    when 60..nil
      '60代以上'
    end
  end
end

次に GitHub Copilot に力を借りる前に、何をテストしたいのかコメントを残します。
そして、参考になるテストコードをちょっとだけ書いておきます。

user_test.rb
require "test_helper"

class UserTest < ActiveSupport::TestCase
  # age が 10 から 70 の間でテストを行いたい
  # age が 60 以上の場合は 60代以上が返ることを確認したい
  test "generation_text" do
    user = User.new(age: 10)
    assert_equal "10代", user.generation_text
  end
end

すると、 GitHub Copilot が以下のような感じでテストコードをサジェストしてくれます。

また GitHub Copilot は他にもサジェストする候補をいくつか持っている場合があります。
パネルを開くと、他候補のコードも閲覧し、選択することができます。
(※ neovim の場合は、 :Copilot panel コマンドで実行できます)

Jest( JavaScript )

まずは以下のようなコードを実装します。

generation_text.js
function generation_text(age) {
  switch (true) {
    case 10 <= age && age < 20:
      return '10代';
    case 20 <= age && age < 30:
      return '20代';
    case 30 <= age && age < 40:
      return '30代';
    case 40 <= age && age < 50:
      return '40代';
    case 50 <= age && age < 60:
      return '50代';
    case 60 <= age:
      return '60代以上';
  }
}
module.exports = generation_text;

こちらも同様に、何をテストしたいのかコメントを残します。
そして、参考になるテストコードをちょっとだけ書いておきます。

generation_text.test.js
const generation_text = require('./generation_text');

// age が 10 から 70 の間でテストをしたい
// age が 60 以上の場合は、60代以上と返ることを確認したい
test('generation_text', () => {
  expect(generation_text(10)).toBe('10代');
});

すると、 GitHub Copilot が以下のような感じでテストコードをサジェストしてくれます。

今回はパネルを開いても複数候補は出てきませんでしたが、一行ずつではなく一気にコードを反映することができました。

おわりに

GitHub Copilot は公式で紹介されている通り、 "Your AI pair programmer" なのだなと実感しました。

「GitHub Copilot が全てのコードを書いてくれる」というわけではないですが、とても優秀な相棒が横で「こういうのはどう?」と都度提案してくれるような感じなので、効率よく開発を進められそうと実感しました。

今後も進化していくツールだと思うので、今後もアップデートを追って、よりスピーディーな開発を目指していきたいなと思いました。

ちなみに

GitHub Copilot を導入した neovim の Docker イメージを、 Docker Hub に公開しています。

https://hub.docker.com/r/tamago3keran/dotfiles

まずは使ってみたいという方は、ぜひ Docker イメージをダウンロードして使ってみてください。

Discussion