hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

リポジトリの履歴を使ってソースコードからテストファイルへの組を推測する

Gitリポジトリの履歴を見て,同時にコミットされる頻度から,ソースコードからテストファイルへの組を推測するのを作った.
あるクラスと同時にコミットされる頻度の高いテストファイルはそのクラスのテストである確率が高いと思われる.


Plackのlib/とt/の結果.変なのあるけど,だいたいうまくいってる.

lib/HTTP/Message/PSGI.pm -> t/Plack-Test/suite.t
lib/HTTP/Server/PSGI.pm -> t/Plack-Middleware/dechunk.t
lib/Plack.pm -> t/Plack-Middleware/content_length.t
lib/Plack/App/CGIBin.pm -> t/Plack-Middleware/cgibin.t
lib/Plack/App/Cascade.pm -> t/Plack-Middleware/cascade.t
lib/Plack/App/Directory.pm -> t/Plack-App/directory.t
lib/Plack/App/File.pm -> t/Plack-Middleware/directory.t
lib/Plack/App/PSGIBin.pm -> t/Plack-Middleware/psgibin.t
lib/Plack/App/URLMap.pm -> t/Plack-Middleware/urlmap.t
lib/Plack/App/WrapCGI.pm -> t/Plack-Middleware/wrapcgi.t


Perlで書いてあるけど,Gitの操作をしてるだけだから,リポジトリのディレクトリと,ソースコードのディレクトリと,テストのディレクトリを指定すれば,対象の言語に問わず使える.
rubygems.orgのapp/model/とtest/を推測した結果.Railsだとだいたい一対一になっていて機械的に決められるから,こういうのいらないと思う.

app/models/.gitkeep -> test/unit/.gitkeep
app/models/dependency.rb -> test/unit/dependency_test.rb
app/models/download.rb -> test/unit/download_test.rb
app/models/linkset.rb -> test/unit/linkset_test.rb
app/models/mailer.rb -> test/unit/web_hook_test.rb
app/models/ownership.rb -> test/unit/ownership_test.rb
app/models/pusher.rb -> test/unit/pusher_test.rb
app/models/rubyforger.rb -> test/unit/user_test.rb
app/models/rubygem.rb -> test/unit/rubygem_test.rb
app/models/subscription.rb -> test/unit/user_test.rb
app/models/user.rb -> test/unit/user_test.rb
app/models/version.rb -> test/unit/version_test.rb
app/models/version_history.rb -> test/unit/download_test.rb
app/models/web_hook.rb -> test/unit/web_hook_test.rb


Perlで,guard-rspecみたいな,autotestみたいなやつがほしくて,ファイルを保存したら自動的にテストが実行してほしかった.
テストを保存したらテスト実行されるだけでなくて,クラスを保存したら対応するテストが自動的に実行されてほしい.
昨日,対応を決めるのに,ファイル名の近さを見て決めるのを試した.↓こんな感じ.

# / _ - . で区切ったときの構成要素の近さ
# 小さいほうが近い
def similarity(a, b)
  delimiter = %r{[/_\-\.]}
  a_fragments = a.split(delimiter)
  b_fragments = b.split(delimiter)
  (a_fragments + b_fragments).uniq.length.to_f / (a_fragments + b_fragments).length.to_f
end

これではうまくいかない場合があって,対応してるファイルだけど名前が似てない場合に別の似たのが実行されたりする.
今日作ったやつだと,同時にコミットされてるなら関係あるだろうという感じで,会社のリポジトリで15000コミットくらいあるリポジトリだとかなりうまくいった.
CSVに保存しておいて,テスト自動で実行するやつから読んで,このクラスならこのテスト,みたいに対応を決めてテスト実行するのに使える.集計するのに時間かかるけど結果はファイルに保存されるのでたまにやればいい.
これでだいたい決めて,変なところだけ,この場合はこっち,というのを手で書いたらだいたいなんとかなりそう.

関連

この前こういうのやってた.こういう雰囲気.

Test::ContinuousっていうCPANモジュールあったけど起動時に全テスト実行して待ってられなかった.設定できるのかもしれないけどよく分からなかった.