Diffblueを使ってユニットテストを自動生成する

2020.09.10

Introduction

Diffblueは、オックスフォード大学からスピンアウトしたスタートアップです。
この企業は、ソフトウェア開発にAIを適応させる事を目指しており、
テスト・バグ修正・リファクタリングなど、従来からある数多くのコーディング作業を
自動化することを目的にしています。

いままでDiffblueはエンタープライズ向けに有料でサービスが提供されていましたが、
先日Diffblue Cover Community Editionを無料で提供開始しました。
これは、IntelliJのplugin形式で提供され、
機械学習を用いてJava用のUnit Testを自動的に生成する機能が含まれています。
(エンタープライズ版とかはCLIやCI integration機能なども持っている)

本稿ではCE版をつかって、Javaの自動ユニットテスト生成を試してみます。

environment

  • IntelliJ IDEA : CE 2020.2

try Diffblue Cover IntelliJ plugin

Diffblue CEはIntelliJのプラグインとして提供されているので、ここから
「Install to IDE」ボタンを押しましょう。クリックするとIDEAで↓のような画面が表示されます。

とりあえず適当なプロジェクトを作成して、テスト対象クラスを作成します。

public class Calc {
    public Integer add(Integer a, Integer b) {
        return a + b;
    }
}

シンプルな足し算メソッドを持つ計算クラス。
プロジェクトエクスプローラ上で右クリックして、Write Testsボタンをクリックします。

シンプルなクラスだけど生成には少しだけ時間がかかります。
.diffblueというディレクトリができており、ここにコードの解析結果とかが保存されてるみたいな感じ。
testディレクトリの中をみると、CalcTestが生成されてます。

public class CalcTest {
    @Test
    public void testAdd() {
        assertEquals(4, (new Calc()).add(2, 2).intValue());
    }
}

ここでCalcを少し修正してみます。引数のnullチェックを追加しました。

public class Calc {

    public Integer add(Integer a, Integer b) {
        if(a == null || b == null) {
            throw new IllegalArgumentException();
        }
        return a + b;
    }
}

再度Write Testsで生成すると、例外が正しくthrowされることを確認するテストが追加されてますね。

public class CalcTest {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testAdd() {
        assertEquals(4, (new Calc()).add(2, 2).intValue());
    }

    @Test
    public void testAdd2() {
        thrown.expect(IllegalArgumentException.class);
        (new Calc()).add(2, null);
    }

    @Test
    public void testAdd3() {
        thrown.expect(IllegalArgumentException.class);
        (new Calc()).add(null, 2);
    }
}

Summary

今回は自動Unit Test生成ツールであるDiffblue CEを使ってみました。
実際の開発ではもっと複雑になっていますし、
生成されるテストの名前や内容などもカスタマイズできるわけではないので
すべてをまかせるわけにはいかないかと思いますが、現時点でもかなり使えるツールではないでしょうか。
(Javadocやアノテーションを使ってテストに影響を与えられたら便利かも?)
また、JavaScriptやPythonなどの他言語にも対応していくようなので、そちらも楽しみです。

もっと複雑なクラスを対象にDiffblueを使ってみた場合、どうなるかは別途試してみたいと思います。

Reference