Java用JUnitテストクラスジェネレータRandoopについて調べてみた

# 概要
Randoopは、Java用テストクラスジェネレータ、指定したクラスのJUnit形式のテストクラスを自動生成する。

# 特徴
ソースから、リグレッションテストと、エラー検知テストを生成する。
> Randoop generates unit tests using feedback-directed random test generation

フィードバック指向のランダムテスト生成だそうです。
OpenJDKのバグを見つけた実績があるそうです。
https://randoop.github.io/randoop/manual/index.html#Introduction

# ユースケース、業務のどこに使えるか（いつ使うか、どのように使うか）
”自前で作るテストケース以外の方法で”デグレを検知できる。

# 注意点、リスク
コードの改修に合わせて、Randoopのテストもメンテナンス（自動生成しなおし）する必要がある。
導入するなら、ある程度自動化が進んでいるプロジェクトの方が良さそう。

# 使い方
### （参考）GitHubプロジェクト
https://github.com/taka2/randoop-sample

SumServiceを利用して、MultiplyServiceを実装しています。
（MultiplyServiceは、SumServiceに依存）

SumService、MultiplyServiceのソース
https://github.com/taka2/randoop-sample/tree/master/src/main/java/randoop_sample

#### 1. テスト生成対象クラスをmyclasses.txtに書く
> randoop_sample.SumService
> randoop_sample.MultiplyService

https://github.com/taka2/randoop-sample/blob/master/myclasses.txt

#### 2. Randoopでテストクラスを生成する
> java -classpath $(RANDOOP_JAR) randoop.main.Main gentests --classlist=myclasses.txt --timelimit=60

生成されたクラス
https://github.com/taka2/randoop-sample/tree/master/src/test/java

#### 3. 生成したクラスをそのまま実行する
これは当然テストが全ケースパスする。

#### 4. SumServiceを修正する
>return a+b;

を

>return a+b+1;

にする。
939/946がfail。SumServiceもMultiplyServiceもデグレしているので、ほとんど全てのテストがfailする。

#### 5. MultiplyServiceを修正する
SumServiceを元に戻して、MultiplyServiceを修正する。

>for(int i=0; i<b; i++) {

を

>for(int i=0; i<=b; i++) {

にする。

482/946がfail。MultiplyServiceのみデグレしているので、半分くらいのテストがfailする。

# 結論
繰り返しになりますが、メリットでデメリットはこんな感じかと。
## メリット
”自前で作るテストケース以外の方法で”デグレを検知できる。
## デメリット
コードの改修に合わせて、Randoopのテストもメンテナンス（自動生成しなおし）する必要がある。

そもそも、ErrorTestが生成されなかったり（エラーがないから？）、RegressionTestも生成されないケースがあったり、結構不安定なので、いまいち未完成なのかなと思ったり。実戦投入は厳しいかなと思う。。

java.util.TreeSetのテストクラス生成に失敗したケース。
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : (java.util.Collection<? extends E>) -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : (java.util.Collection<? extends E>) -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : (java.util.Collection<? extends E>) -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : (java.util.Collection<? extends E>) -> java.util.TreeSet<E>
> Instantiation error for operation <E> java.util.TreeSet<E>.<init> : () -> java.util.TreeSet<E>
> ...

# 参考資料
- Randoop:  Automatic unit test generation for Java
    - https://randoop.github.io/randoop/
- GitHub - randoop/randoop: Automatic test generation for Java
    - https://github.com/randoop/randoop
- AWS Well-Architected フレームワークによる クラウド ベスト プラクティス
    - https://d0.awsstatic.com/events/jp/2017/summit/slide/D2T1-1.pdf
    - Randoopは、このドキュメントで見つけました。