JenkinsでFEST-Swingを実行する

FEST-SwingはJava Swingのテストフレームワークです。
FEST-Swing

Seleniumっぽい感じでSwingをテスト出来るフレームワークです。

で、これをJenkinsでCIしたいわけですが、Seleniumと同じようにウィンドウが必要になります。
いろいろやって、上手く動くところまで出来たので、ここに残しておきます。

Windowsの場合

FESTのドキュメントにあるんだけど、なんかようわからんってことで、以下方法で出来たのでとりあえずはこれでよかった。

  • 単純にJenkinsが動いてるサーバにログインし続ける。

ただしログアウトしたらテストが失敗するので、常に開いた状態じゃないとだめ。
StackOverFlowあたりで「セキュリティについては気にすんなw」みたいな英語の回答があったw

Linux/Debian などの場合

今回はDebian系のOSでやってたんだけど、とても簡単に出来ることがわかった。

まずすごく参考になったのが、この記事
JenkinsでFEST-Swing - やざわラボブログ この方法はたぶんGUI無しのときのやり方と思う。

Debian派生のOSでGUI有りでインストールしていろいろして出来たので以下に書く。

Debian GUIでインストールした時の話

まずGUI有りの場合に何も設定しないで実行すると、FESTが「X11変数(DISPLAY)が設定がされていません」的なエラーで失敗します。
ここは素直にDISPLAY環境変数に設定してあげましょう。

ちなみに私の環境だとコンソールでecho $DISPLAYしたら:0.0と出ました。
なんで設定されてるのにうまく動かんのじゃとは思ったけど、EnvInject Pluginという環境変数をJOBごとに設定できるプラグインで設定してあげた。

ちょっとJenkinsが手元には無いので、この画像のProperties Contentに、DISPLAY=:0.0と設定したら動いた!!! Properties Content


ということで、Swingアプリって今あんまり作ってる人いないのかもしれないけど、レガシーなアプリをCIしたい時とかに参考になればと思います。

JavaFXで作り直させてくれぇぇぇぇぇぇぇ!!!!!!

おわり

GradleでマルチプロジェクトのJUnit ReportとJacoco Reportを出す

Gradleのマルチプロジェクトを使う必要があって、だいぶハマったので記事に残しておこうと思う。

マルチプロジェクト構成

  • root
    • myproject
    • myproject-test

ここでは、実際のディレクトリとしてフラットに存在する例

$ ls
myproject  myproject-test  root

root

親プロジェクト。 最初はsettings.gradleしか持っていない状態。

settings.gradle

includeFlat "myproject", "myproject-test"

includeで階層型になる。参考

myproject

プロダクトコードプロジェクト。 ここにもJUnitテストコードがあったりする。

myproject-test

myprojectプロジェクトのテスト用プロジェクト。 単体・結合・総合テスト用JUnitが置かれたりする。

現状の問題点

このままgradle test jacocoTestReportしたら、myproject・myproject-testのbuildにそれぞれレポートが出力される。

  • root
  • myproject
    • build
      • jacoco - test.exec
      • reports
        • jacoco - html - index.html
        • tests - index.html
  • myproject-test
    • build
      • jacoco - test.exec
      • reports
        • jacoco - html - index.html
        • tests - index.html

これだとJenkinsで管理するときにレポートが上手く行かなくて困る。

myprojectとmyproject-testのJUnit,Jacocoレポートを一括、まとめて、統合、結合でレポートしたい!

JUnit Report

23.13. テスト - gradle userguide
-> 例23.14 Creating a unit test report for subprojects

ここに書いてあるんだけど、なんでか英語のまま!(激怒)

root/build.gradle

subprojects {
    apply plugin: 'java'

    test {
        // 別タスクで一括で出力する
        reports.html.enabled = false
    }
}

task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    reportOn subprojects.tasks.test
}

はまりどころは、apply plugin: 'java'が必須というところ。 これはGradleの知識がまだ不足してたからだけど、rootからsubprojectを見た時に定義されてないとダメポ

myprojectとかmyproject-testでapply plugin: 'java'してるからrootではいらないかな?

とかいうのが落とし穴でした。

結果レポート出力

ということで、rootにtestReportというTaskを追加したので、実行する。

$ cd root

$ gradle clean test testReport
:myproject:clean
:myproject-test:clean
:myproject:compileJava
:myproject:processResources UP-TO-DATE
:myproject:classes
:myproject:compileTestJava
:myproject:processTestResources UP-TO-DATE
:myproject:testClasses
:myproject:test
:myproject-test:compileJava
:myproject-test:processResources UP-TO-DATE
:myproject-test:classes
:myproject-test:compileTestJava
:myproject-test:processTestResources UP-TO-DATE
:myproject-test:testClasses
:myproject-test:test
:testReport

BUILD SUCCESSFUL

Total time: 19.366 secs
  • root
    • build
      • reports
        • allTests - index.html
  • myproject
  • myproject-test

myprojectmyproject-testにはreportsは出力されてない。OK

f:id:clash_m45:20150124161734p:plain

Jacoco Report

お次はJacoco Reportをまとめて出力します。
maven時代はcovertura使ってたんだけどなんだか最近はjacocoがいいのかな?ってことでこちらを使ってます。

このGithub Gistを参考にしました。
Aggregated Jacoco reports in a multi-project Gradle build

あとは公式説明書
Chapter 34. The JaCoCo Plugin

DSLも見ないと全然わかりません。
DSL - JacocoReport

Projectのプロパティも使うので、DSL見ます。
DSL - Project

root/build.gradle

allprojects {
    apply plugin: 'java'
    apply plugin: 'jacoco'

    repositories {
        jcenter()
    }
}

subprojects {
    test {
        // 別タスクで一括で出力する
        reports.html.enabled = false

        jacoco {
            //execをrootprojectに出力する
            destinationFile = file("$rootProject.buildDir/jacoco/${project.name}.exec")
        }
    }
}

task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    reportOn subprojects.tasks.test
}

task jacocoRootReport(type: JacocoReport) {
    dependsOn = subprojects.test
    //レポート対象はmyprojectのソース
    additionalSourceDirs = files(project('myproject').sourceSets.main.allSource.srcDirs)
    sourceDirectories = files(project('myproject').sourceSets.main.allSource.srcDirs)
    classDirectories = files(project('myproject').sourceSets.main.output)
    //レポートのためのexecはjacocoTestReportタスクの設定を利用
    executionData = files(subprojects.tasks.jacocoTestReport.executionData)
    reports {
        html.enabled = true
        xml.enabled = false
        csv.enabled = false
    }
}
  • ハマリポイント
    • rootprojectにもjacoco pluginが必要
      • jacocoRootReportタスクでjacocoのクラスパスを要求されるので、plugin applyしておかないと怒られます。
    • カバレッジ対象はmyprojectのソースにしたい
      • projectのプロパティの使い方がいまいちよくわからないのが問題で、かなりはまった。
    • jacoco execをrootprojectに出したい
      • ハマった原因はやっぱりprojectのプロパティがよくわからなかったから。

結果レポート出力

結果がわかりやすいようにJavaファイルを変更しました。

それではタスク実行。

$ cd root

$ gradle clean jacocoRootReport
:clean
:myproject:clean
:myproject-test:clean
:myproject:compileJava
:myproject:processResources UP-TO-DATE
:myproject:classes
:myproject:compileTestJava
:myproject:processTestResources UP-TO-DATE
:myproject:testClasses
:myproject:test
:myproject-test:compileJava
:myproject-test:processResources UP-TO-DATE
:myproject-test:classes
:myproject-test:compileTestJava
:myproject-test:processTestResources UP-TO-DATE
:myproject-test:testClasses
:myproject-test:test
:jacocoRootReport

BUILD SUCCESSFUL

Total time: 21.308 secs
  • root
    • build
      • jacoco
        • myproject-test.exec
        • myproject.exec
      • reports
        • jacoco - jacocoRootReport - html - index.html

f:id:clash_m45:20150124161706p:plain

myprojectのソースだけがカバレッジ対象になってます!


なんつーか一番はまりやすいのはprojectのプロパティの使い方だなーとかなり思ってます。
略式記法がわかりづらすぎる・・・

はてなダイアリーからブログに移行しました。

Atom Editor Markdown Perview の フォントについて(Windows)

AtomWindowsにも対応したので、早速メインエディタとして使ってみてます。

で、気づいたんですが、最初から入ってるMarkdown Previewの漢字表示が中国語っぽくね?って話です。
海外製のエディタでよくある、漢字が中国語フォントだーってやつですね。

ってことでフォントを指定してあげていい感じにしたいと思います。


Markdown Previewのフォントを変える

Markdown Previewのパッケージ内にあるlessを変更します。

○Markdown Previewのフォルダを開く
設定画面(Ctrl + ,)を開き、
1. "makrdown"と入力し、パッケージを検索する。
2. [Open to Atom]をクリックすると、パッケージのフォルダがAtomで開く。


○lessファイルのfont-familyにフォントを追加
1. stylesheets -> markdown-preview.less を開く。
2. 3行目に"font-family"があるので、そこに好きな日本語フォントを追加する。
3. パッケージを読み込み直す。(Ctrl + Alt + r)

変更前

@font-family: "Helvetica Neue", Helvetica, sans-serif;


変更後

@font-family: Consolas, Meiryo, "Helvetica Neue", Helvetica, sans-serif;

私は最近Consolasという等幅フォントが好きなので、それにしています。
Consolasは日本語フォントが無いので、後ろにメイリオを付けてます。


以上、簡単ですがMarkdown Previewのフォント変更でした。

    • -

仕事用にmajestouch 赤軸使ってから家のキーボード(Microsoft)が打ちづらーてしゃーない......
あとhetenaがmarkdownに対応ってブログのほうだけなんすね。辛い

vagrant windows環境でSSH for Teraterm

最近流行りのchef soloを入門するべく、『入門Chef Solo - Infrastructure as Code』を購入して絶賛入門中です。

で、chef soloを試すためのVM環境をセットアップするために、
vagrantを使って、Cent OSを入れてみました。
# 本では4章で解説

で、vagrant sshssh接続できるはずなんですが、windows環境だとssh無いよ!ということで失敗します。
こんな感じで。

>vagrant ssh
`vagrant ssh` isn't available on the Windows platform. You are still able
to SSH into the virtual machine if you get a Windows SSH client (such as
PuTTY). The authentication information is shown below:

Host: 127.0.0.1
Port: 2222
Username: vagrant
Private key: C:/Users/hogehoge/.vagrant.d/insecure_private_key

そんで、ggった結果puttyだとかcygwinだとか、いくつかヒットするものの
正直・・・めんどくせぇ・・・・です。


あれ?sshしたいだけならTeratermでいいんじゃね?

vagrantの設定ファイル(Vagrantfile)をchef solo入門通りにいじったなら、

config.vm.network :hostonly, "192.168.50.2"

みたいな記述があるはずです。
これが作った仮想サーバのIPなので、teratermで接続して、
アカウントは id / pass : vagrant / vagrant です。

これでいいじゃん!


別にアフェってるわけでもないのに載せちゃう

まだvagrantでゲストOS作るしかしてないから、もしかしてchef-soloがssh必須だったらダメですね(^q^)

ログ出力 "したい" 時と "したくない" 時を実装

log4jでログ出力してて、例えばコンソールアプリケーションを作ってる時に、
あるアプリではコンソール+ログファイル両方出力したいけど、
もう一方のアプリではコンソールには出さなくて、ログファイルにだけ出したい、ってときがある。

そしてその2つのアプリは同じロジックを呼ぶ、つまり呼ばれるロジックはログを出力する時としない時がある。
うーん、log4jの標準機能ではクラス単位での切替くらいしかできないよなー、ってことで、こんな感じにしたらできたのでご紹介。
# もっとCoolにできるなら教えてください。


clashm45/log4j_mute · GitHub

MyLoggerクラスを作って、

public class MyLogger {
  private Logger logger = null;
  private static final String NoConsole = "NoConsole";
  
  private MyLogger(Class<?> clazz){
    logger = Logger.getLogger(clazz.getName());
  }

  private MyLogger(String prefix, Class<?> clazz){
    logger = Logger.getLogger(prefix+"."+clazz.getName());
  }

  public static MyLogger getInstans(Class<?> clazz){
    return new MyLogger(clazz);
  }

  public static MyLogger getInstansNoConsole(Class<?> clazz){
    return new MyLogger(NoConsole, clazz);
  }

  public void info(String msg){
    logger.info(msg);
  }
~~~
}

log4j.xml でこうする

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

  <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
    <param name="Target" value="System.out" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d %5p %c - %m%n" />
    </layout>
  </appender>

  <appender name="file" class="org.apache.log4j.FileAppender">
    <param name="File" value="target/App.log" />
    <param name="Append" value="true"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d %5p %c - %m%n" />
    </layout>
  </appender>

  <category name="log4j_mute">
    <priority value="info"/>
    <appender-ref ref="stdout"/>
    <appender-ref ref="file"/>
  </category>

  <category name="NoConsole">
    <priority value="info"/>
    <appender-ref ref="file"/>
  </category>

</log4j:configuration>

こんなロジッククラスを作る。
LogicA

public class LogicA {
  private static MyLogger logger = MyLogger.getInstans(LogicA.class);
  public static void process(){
    logger.info("処理A!!");
  }
}

LogicB

public class LogicB {
  private static MyLogger logger = MyLogger.getInstans(LogicB.class);
  public static void process(){
    logger.info("処理B!!");
  }

  public static void mute(){
    logger = MyLogger.getInstansNoConsole(LogicB.class);
  }
}

そしてロジックを利用するアプリケーションでこんな風にする。

public class App{
  public static void main( String[] args ) {
    LogicA.process();
    LogicB.process();
    LogicB.mute();
    LogicB.process();
  }
}

処理結果:コンソール

$ java -cp "src/main/resources;target/log4j_mute-1.0-SNAPSHOT-jar-with-dependencies.jar" log4j_mute.App
2012-12-18 14:39:29,461 INFO log4j_mute.LogicA - 処理A!!
2012-12-18 14:39:29,462 INFO log4j_mute.LogicB - 処理B!!

処理結果:ログファイル

$ cat target/App.log
2012-12-18 14:39:29,461 INFO log4j_mute.LogicA - 処理A!!
2012-12-18 14:39:29,462 INFO log4j_mute.LogicB - 処理B!!
2012-12-18 14:39:29,463 INFO NoConsole.log4j_mute.LogicB - 処理B!!

カテゴリを使ってログ出力方法を変えてるわけです。

MacBookAirでMaven - Settings.xmlはどこに?

なんかMacBookAirには最初からMaven3が入っているので使ってみよー。。。。
MacBookAir(SnowLeopard)にmavenをインストール - matsuyamahirokiの日記

と、したらあれ?Settings.xmlってwindowsの場合は最初からなかったっけ?記憶違い?
ググったら以下回答が、
Where is Maven' settings.xml located on mac os? - Stack Overflow

  1. "/User/%username%/.m2/"に作成する
  2. "/usr/share/maven/conf/"に最初からある

1. + 2. = "/User/%username%/.m2"で"ln -s /usr/share/maven/conf/settings.xml settings.xml"を実行する

ってのが一番キレイかもですね!

NetBeansでtoStringの自動生成

IDEにはsetter/getterや、toStringのOverrideなどを自動生成する機能がある。

今回JavaFXを触るためにnetBeansインスコして、使ってみてたんだけど、この機能が見つからない!!!
Twitterで教えて!って叫んでみたら教えてくれる親切な方が!


netBeansでは Alt + Insert で以下メニューが表示されました。

例えばtoStringの生成はこんなのがポップして、

バーンとぉ! こんなのが生成されます!!

@Override
public String toString() {
    return "Busyo{" + "name_sei=" + name_sei + ", name_na=" + name_na + ", tosotsu=" + tosotsu + ", buryoku=" + buryoku + ", tiryaku=" + tiryaku + ", seiji=" + seiji + ", giri=" + giri + '}';
}

ちゃんと日本語のマニュアルも整備されていたので、じっくり読めばいろいろショートカットキーも覚えると思う。
http://netbeans.org/kb/docs/java/editor-codereference_ja.html#codecompletion
ショートカットキーの一覧/補完省略名なんかの一覧もPDFで見つかった。
http://usersguide.netbeans.org/shortcuts_ja.pdf




eclipseならJavaエディタを右クリックから[ソース]→各機能(以下画像のメニュー) をクリックすると色々とできる。

ちなみにeclipseだとStringの連結だけじゃなく、StringBuffer/StringBuilderでの連結も選べるからこの部分ではeclipseに軍配が上がるかな。
バーンとぉ!

@Override
public String toString() {
    StringBuilder builder = new StringBuilder();
    builder.append("Busyo [name_sei=");
    builder.append(name_sei);
    builder.append(", name_na=");
    builder.append(name_na);
    builder.append(", tosotsu=");
    builder.append(tosotsu);
    builder.append(", buryoku=");
    builder.append(buryoku);
    builder.append(", tiryaku=");
    builder.append(tiryaku);
    builder.append(", seiji=");
    builder.append(seiji);
    builder.append(", giri=");
    builder.append(giri);
    builder.append("]");
    return builder.toString();
}


確認環境:
netbeans / 7.2.1
eclise / 3.7 Indigo