2020年8月29日土曜日

Studio One 5 ArtistでScales & Chords (Reason 11 LiteのRack Plugin) を使う

音楽のコード(和音)の生成規則はわかったけれど、鳴らそうとすると腰が重くなる。でも鳴らさないとどんな音かわからない。好きな音源でルート(根音)と生成ルールを指定したら該当するコードを鳴らしてくれたらいいのに!

これをPresonusのハードウェア製品 (例えばオーディオインタフェースStudio c24) にバンドルされているDAW Studio One 5 Artistで、KORGのMIDIキーボードmicroKey-25にバンドルされているReson Lite 11のScales & Chordsで実現する方法。

Studio One 5 Prodessionalならコード・トラックがあるのできっと不要のノウハウ。コードを覚えていない初学者でも楽にそれっぽい音を鳴らしたいと思ってあれこれ試した結果。

しばらくしたら忘れそうなので覚書として残しておく。


Studio One 5 ArtistがVST3対応し、Reason 11 LiteにReason Rack Plugin(VST3プラグイン)が含まれるようになったので、下記の手順で実現できる。
  1. Reason Rack PluginでScales & Chordsのインストゥルメンタルトラックを作る
  2. 鳴らしたい音源のインストゥルメンタルトラックを作る
  3. 新規インストゥルメンタルトラックを作成し、次のとおり入出力を設定する
    • 入力:Reason Rack Plugin | Event Out
    • 出力:既存のインストゥルメント > 「2」で作ったインストゥルメンタルトラック
  4. 「3」で作ったインストゥルメンタルトラックを選択した状態でキーボードのルートを押す

Scales & Chordsよりあとで見つけたChordSpace Homeの方が使い込み甲斐があるかも知れない。各音のベロシティを変えられたりと細かく制御できる。

もっといいやり方があったら@SO_Cにリプライください。

2017年10月21日土曜日

JShellを使ってJavaだけでSelenium (ChromeDriver) を動かす。

はじめに

Mirror House Lab: Nashornを使ってJavaScriptを書いてSelenium (ChromeDriver) を動かす。で、
「もうすぐjshellを含むJava SE 9がリリースされてJavaをスクリプトとして実行できるようになるだろうに、何をやっているんだ」という気もしているけれど、Java SE 8環境ですぐに動かしたかったので。
と言っていた。

Java SE 9がリリースされたのでJShellで動かす方法について書く。

環境と準備

環境は以下の通り。
  • OS: Windows 10 (64bit)
  • JDK: 9
  • Selenium Standalone Server: 3.6.0
  • Chrome: 61
  • ChromeDriver: 2.33

SeleniumとChromeDriverの準備作業は変わらない。ただしNashhornとJShellでクラスパスの通し方が異なる(後述)。JDKとChromeはインストール済みとする。

Selenium: DownloadsからSelenium Standalone Serverをダウンロードする。保存先フォルダにパスを通すのは必須ではない。JShellはオプションでもコマンドでもクラスパスを指定できる。この記事ではコマンドで指定する方法を採用する。

ChromeDriver: Downloads - ChromeDriver - WebDriver for Chromeから、chromedriver_win32.zipをダウンロードして展開する。Windows 64bit用は提供されていないので32bit用を使う。こちらも保存先にパスを通すのは必須ではない。Javaの場合、プロパティに設定できる。このエントリィではその方法を採用する。

サンプルコード

クラスパスを通すのはJShellのコマンド。あとはJavaなので取り立てて言うことはない。
// jshell-selenium.jsh
/env -class-path C:\path\to\selenium-server-standalone-3.6.0.jar;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

String pathToChromeDriver = "C:\\path\\to\\chromedriver.exe";
System.setProperty("webdriver.chrome.driver", pathToChromeDriver);

ChromeDriver driver = new ChromeDriver();
driver.get("http://www.google.com/xhtml");
Thread.sleep(5000);
WebElement searchBox = driver.findElement(By.name("q"));
searchBox.sendKeys("ChromeDriver");
searchBox.submit();
Thread.sleep(5000);
driver.quit();

実行方法

最初はJShellを起動して、下記を実行する。
> /open C:\path\to\jshell-selenium.jsh

2回目以降、そのまま繰り返すときは/reloadコマンド。

スクリプトファイルを修正して再実行するなら、/resetコマンドを実行してから、/openコマンド。JShellは/listで表示されるコードを実行するのだけれど、/openコマンドは追記して実行するので、もう1回/openコマンドでスクリプトファイルを読み込むと2回実行される。

クラスパスの通し方

クラスパスは、JShell起動時にコマンドラインオプションで渡すこともできる。External Codeの"Setting The Class Path"を参照。

Java 9なのでクラスパスではなくてモジュールも使える(External Codeの"Setting Module Options")。でも、そのモジュールをまだよく分かっていないので、まずはそちらから調べないと。

感想

Javaで書けるので言語差分を考えなくてよいのと、ちょっとデバッグしているときにJShell上で補完が効くのが助かる。

References

2017年7月15日土曜日

Nashornを使ってJavaScriptを書いてSelenium (ChromeDriver) を動かす。

はじめに

開発環境ではない環境で、ちょっとしたブラウザ操作を自動化するのに使った方法について書く。

具体的には、Nashorn (Java SE 8で追加されたJavaScriptエンジン。Rhinoの後継) を使い、JavaScriptを書いてSelenium Standalone Serverを呼び出し、ChromeDriverでChromeを自動操作する方法。

「Selenium Standalone ServerはJarなのだから、素直にJavaから呼んだら?」とか、「JavaScriptで書くならSelenium Client & WebDriver Language BindingsのJavaScript (node)を使うのが自然では?」とも思うのも、ごもっとも。自分もそう思う。

それでもこの方法を調べたのは、環境準備が楽だから。JREさえインストールされていれば、あとはSeleniumをダウンロードするだけ。Eclipse, JDK, node.jsどれも必要ない。

「もうすぐjshellを含むJava SE 9がリリースされてJavaをスクリプトとして実行できるようになるだろうに、何をやっているんだ」という気もしているけれど、Java SE 8環境ですぐに動かしたかったので(※2017/10/21追記: JShellでも動かしてみた)。

環境と準備

環境は以下の通り。
  • OS: Windows 10 (64bit)
  • JRE: 8
  • Selenium Standalone Server: 3.4.0
  • Chrome: 59
  • ChromeDriver: 2.30

SeleniumとChromeDriverの準備作業は以下の通り。JREとChromeはインストール済みとする。

Selenium: DownloadsからSelenium Standalone Serverをダウンロードする。保存先フォルダにパスを通すのは必須ではない。Nashornを起動するときにオプションでクラスパスを指定できる。この記事ではその方法を採用する。

ChromeDriver: Downloads - ChromeDriver - WebDriver for Chromeから、chromedriver_win32.zipをダウンロードして展開する。Windows 64bit用は提供されていないので32bit用を使う。こちらも保存先にパスを通すのは必須ではない。Javaの場合、プロパティに設定できる。このエントリィではその方法を採用する。

サンプルコード

ポイントはJavaクラスへのアクセス。標準JavaパッケージのクラスにアクセスするにはFQCNを使う。それ以外のクラス(ここではorg.openqa.seleniumパッケージのクラス)にアクセスするには、Java.type('FQCN')を使う。
// nashorn-selenium.js

// グローバル変数/関数を作らないため即時関数呼び出し。
// 『メンテナブルJavaScript』の「6.4 0-グローバルのアプローチ」参照。
// この使い方の場合、ここまでする必要もないかもしれないけれど一応。
(function() {
  var ChromeDriver, By;
  var pathToChromeDriver, driver, searchBox;

  // Javaのimport相当。
  ChromeDriver = Java.type("org.openqa.selenium.chrome.ChromeDriver");
  By = Java.type("org.openqa.selenium.By");

  // chromedriver.exeへのパスをプロパティに設定。
  // chromedriver.exeが環境変数PATHに指定しているフォルダにあるなら省略できる。
  pathToChromeDriver = 'C:\\\\path\\to\\chromedriver.exe';
  java.lang.System.setProperty('webdriver.chrome.driver', pathToChromeDriver);

  // 実行内容は、
  //   Getting started - ChromeDriver - WebDriver for Chrome
  //   https://sites.google.com/a/chromium.org/chromedriver/getting-started
  // と同じ。
  // Chromeを起動して、Googleで"ChromeDriver"を検索して、Chromeを終了する。
  driver = new ChromeDriver();
  driver.get('http://www.google.com/xhtml');
  java.lang.Thread.sleep(5000);
  searchBox = driver.findElement(By.name('q'));
  searchBox.sendKeys('ChromeDriver');
  searchBox.submit();
  java.lang.Thread.sleep(5000);
  driver.quit();
}());

実行方法

コマンドプロンプトからjjs (nashornを起動するツール) を実行する。その際、-cpオプションでSelenium Standalone Serverをクラスパスに追加しておく。
> jjs -cp "C:\path\to\selenium-server-standalone-3.4.0.jar" nashorn-selenium.js

感想

もろもろの補完が効かないから、スクリプトを書くのが疲れる。けれど、IDE入れるなら環境を整えて、Javaから動かせばよいので、どちらの手間を惜しむかか。

References

2016年11月11日金曜日

設計アプローチ (POA/DOA) 再考

最近、業務システムの設計の流れについて考えている。自分の頭の整理のため、それを書き出してみた。結論だけ乱暴に言うと、ユーザと設計を始める取っかかりはUI。でも、並行して既存データも分析する必要がある。その結果、最初に設計が安定してくるのがデータで、そこからUIや機能にフィードバックされる流れになるだろうと考えている。

2つの設計アプローチ

業務システムの設計アプローチとして、POA (Process Oriented Approach)とDOA (Data Oriented Approach)という考え方がある。POAでは業務プロセスつまり仕事の手順から手をつけていく。DOAではデータつまり帳簿から手をつけていく。

自分には、DOAの方が理に適っていると思える。一般的な傾向として、業務プロセスよりデータの方が安定しているし、変更の影響が大きいからだ。だからデータベースに早めに安定した設計を与えたい。そうしないと、プログラミングできない。
データ構造がダメな状態で、プログラミングによって挽回することはできません。
――『達人に学ぶDB設計』
『データベース・リファクタリング』にもどうようの主張があった。

機能が先かデータが先か

ところが、先日『はじめよう!要件定義』を読んでいたら、UI・機能・データを、
  1. 何はともあれUI
  2. 操作に対して機能が動作すること
  3. 機能に必要なデータ揃っていること
の順で設計していっている。確かに、ゴールから逆算するとこうなる。『実践テスト駆動開発』からの孫引きだが、こんな言葉もある。ユニットレベルの粒度で考えても、データアクセスレイヤをモック化するのはユニットテストの常套手段だ。
何かを設計するときには、常にもうひとまわり大きなコンテキストの中で考えること。椅子ならば部屋の中にあることを考える。部屋なら家の中、家なら環境の中、環境なら都市計画の中。
――エリエル・サーリネン

並走すればいい

データモデリングの視点で見ると、これはトップダウンアプローチだ。普通は、これだけでは足りない。既存データがあるからだ。そこには、UIには表れない、他のシステムから連携されるデータが格納されているかもしれない。過去の業務プロセスに由来する、今は使わないデータが格納されているかもしれない。ここで、ボトムアップアプローチつまり既存データの分析も必要になる。

ボトムアップアプローチでデータが変わるとどうなるか。既存データは変えられないから機能やUIにフィードバックがかかることになる。絵にするとこのようなイメージ。これならしっくり来る。


データベース恐怖症?

ここからは設計を離れて人の話。UIや機能の分析と、既存データの分析を一人で両方やる必要はないにしろ、最終的には統合して一貫した設計に仕上げないと動かない。だから、分担して情報交換することになる。そのときのことを考えると、もう少しデータベース設計の知識が広まるといいな、と思う。

データベース設計をできてプログラミングできない人は見たことがないけれど、逆はよく見かける。漢(オトコ)のコンピュータ道: データベースについてのそもそも論や『SQLアンチパターン』を見ると、隔たりは大きそうだけれど。

refernces


2015年10月17日土曜日

Windows10でRedPen (CLI) を使う

マニュアルなどの文書チェックツールRedPenをWindows10のコマンドラインから使う方法について記載する。Windows環境で動かそうとしたら2, 3引っかかったので、その解消方法メモ。あと、オマケとしてサクラエディタで編集中のファイルをチェックする方法も。

利用環境は次のとおり。
  • RedPen 1.4.0
  • Windows 10
  • Java 1.8.0 update 45

1. インストール

Java 1.8.0以降をインストールしておく。環境変数JAVA_HOMEも設定しておくこと。

リリースページから、redpen-1.4.0.tar.gzをダウンロードして、任意のフォルダに展開する。以降、展開したフォルダをINSTALL_DIRと表記する。

2. 微調整

そのまま実行すると次の2つの問題があるので、微調整する。
  • チェックメッセージが文字化けしている。
  • カレントディレクトリにjsフォルダが作成される。
文字化けを解消するには、INSTALL_DIR\bin\redpen.batの12行目に-Dfile.encoding=UTF-8を追加する。これでチェックメッセージの文字化けが解消する (コマンドプロンプト上だと、代わりに実行ログが文字化けしてしまうけれど許容している)(完全には解決できなかったのが気持ち悪いけれどIssueを出してみた)。
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8
jsフォルダの作成を抑止するには、設定ファイルINSTALL_DIR\conf\redpen-conf-ja.xmlの<validator name="JavaScript" />を次のように書き換える。JavaScriptで実装されたチェックルールを使う予定がないなら、代わりに消しても良い。
<validator name="JavaScript">
    <property name="script-path" value="INSTALL_DIR\js" />
</validator>
メモ: Writing RedPen extension with JavaScript | RedPen BLOGRedPenのValidatorをJavaScript で書くには - ククログ(2015-08-29)を読むと、プロパティscript-pathが優先で、未指定なら環境変数REDPEN_HOME\jsを参照しそうなものだけれど、未指定だとカレントディレクトリ\jsを参照しようとして存在しないときは作成してしまうみたい (このコミットを見ると、次のヴァージョンではログが出るだけになりそう)。詳しい原因は不明。環境変数REDPEN_HOMEはredpen.bat内で設定されているから、設定漏れではなさそう。redpen.batにecho %REDPEN_HOME%を追記してみたら、ちゃんとINSTALL_DIRが表示されるているし (ForkしてUnit Testを書いてみたけれどNGだったので、Issueを出してみた)。

3. 実行確認

任意のディレクトリ (微調整の確認のため、最初はINSTALL_DIR以外がよい) でコマンドプロンプトを実行し、次のコマンドを実行する。
INSTALL_DIR\bin\redpen -c INSTALL_DIR\conf\redpen-conf-ja.xml INSTALL_DIR\sample-doc\ja\sampledoc-ja.txt
下記のような実行結果が表示されるはず。
(前略)
[2015-10-17 20:15:52.673][INFO ] cc.redpen.validator.JavaScriptValidator - JavaScript validators directory: INSTALL_DIR\js
sampledoc-ja.txt:1: ValidationError[SentenceLength], 文長("101")が最大値 "100" を超えています。 at line: 最近利用されているソフトウェアの中には複数の計算機上で動作 (分散)するものが多く存在し、このような分散ソフトウェアは複数の計算機で動作することで大量のデータを扱えたり,高負荷な状況に対処できたりします。
(以下略)

(オマケ) サクラエディタで編集中のファイルのチェック

[ツール] > [外部コマンドを実行]で、下記の通り設定して[実行]ボタンを押すと、編集中のファイルをチェックできる。一度実行すれば、Ctrl+F, Enterでチェックできて便利。
名前: "INSTALL_DIR\bin\redpen.bat" -c "INSTALL_DIR\conf\redpen-conf-ja.xml" "$F"
標準出力を得る: チェックボックスをオンにして"UTF-8"を選ぶ。
標準出力リダイレクト先: アウトプットウィンドウ
ちなみに、アウトプットウィンドウ上だと実行ログもチェックメッセージも文字化けしない。

2015年8月9日日曜日

テストデータを管理する方針

『継続的デリバリー』の、テストデータの管理についての記述を整理してみた。該当する章節は、
  • 12.5 テストデータを管理する
  • 12.6 データの管理とデプロイメントパイプライン
それから12.5から参照されている、
  • 8.5.1 受入れテストにおける状態
の3箇所。特に断りの無い限り、『継続的デリバリー』のいう受入れテストのデータ管理を念頭に置いている。

テストデータの管理で問題となるのは、1) パフォーマンス、2) テストの分離の2つ。xUTPだとそれぞれSlow TestsSeparation of Concernsに対応しているように思う。

どちらの問題でも、真っ先に原因として挙がるのがデータベース。ユニットテストならデータベースアクセス移譲先 (デザインパターンDAO相当) をテストダブルで置き換えられる。これはパフォーマンスにも分離にも効く。DBの状態も含めてテストしたい場合、インメモリDB (H2, SQLite, JavaDBなど) を使うこともできる。

データベースに限らず、テストとデータのつながりを管理するアプローチには、次の3つがある。
  1. テストの分離: 各テスト用のデータは、そのテストからしか見えないようにする。
  2. 順応型テスト: テストがデータ環境を調べ、実際のデータに合わせて振る舞うようにする。
  3. テストの順序づけ: テストの実行順序を予め決めておいて、一つ前のテストの出力を次のテストの入力とする。
スケールするのは1だけだと言っている。3は分かりやすい無理ゲー。こんな強く依存していたらスケールさせられない。2は一見良さげに見えるけれど、分離しきれていないと、別のテストで実際のデータが思いもよらない状態になっていることがある。xUTPでもTest SmellsとしてConditional Test Logicが挙がっている。

「テストの分離」のためには、まずテスト終了時にテスト前の状態に戻すとある。そうしないと、次のテストに今のテストのデータが見えてしまう。ただこれにはオプションもある。『システムテスト自動化標準ガイド』や『実践テスト駆動開発』では、テスト対象が登録したデータはテスト終了時に消さずに、テスト開始時に消すことを勧めている。もう一つの方法は、データを機能分割すること。これができるかどうかは、テスト対象の特性に強く依存する。

データを分割し、巨大で複雑なデータ構造への依存を減らすには、まずデータを整理しないといけない。著者はこんな風に言っている。
何よりもまず、プロダクションデータのダンプを取得して受入れテスト用にテストデータベースに投入したいという誘惑に負けないこと。
統制のとれた最小限のデータセットを保守しよう。
整理の取っかかりとなるのが、次の3種類のデータの区別。
  1. テスト固有のデータ: 一意でなければならない。テストの分離の手段になる。
  2. テストが参照するデータ: テストには関係するがふるまいには影響しないデータ。そこら中で使われるマスタデータ類を指していると思う。
  3. アプリケーションが参照するデータ: アプリケーションを立ち上げるのに必要なデータ。

一言で言うと、正しく動くと分かっている(契約による設計の言葉を使うと、事前条件を満たしている)開始位置を特定し、テスト開始時にその状態を復元する。言ってしまえばこれだけなんだけれど、そのためにはテスト対象とテストデータをよく理解する必要がある。それも一部のテストだけじゃない。うまくテストを分離するには、全体を俯瞰する必要がある。

なお、その開始位置を復元するのには、アプリケーションのAPIを利用するよう勧めている。理由は3つ。
  • システムを矛盾した状態に持ち込ませない。
  • データベースやAPIのリファクタリングの影響を避けられる。
  • APIのテストにもなる。
できないときは、事前条件をアサートする防御的なテストコードにしたり、アサートを相対的(例えば、レコードが3件あることではなくて、3件増えたことにする)にしたりする。

References


2015年8月2日日曜日

JUnitのRunner (Enclosed, Theories, Categories) を併用したときの動き

JUnit4の次のRunnerの関係を整理してみた。なお、JUnitのバージョンは4.12。
  • Enclosed
  • Theories
  • Categories

論理的にテストクラスを分類しつつ、並列化するための分類もしたくなることがあるので、JUnitの仕組みでどこまでできるか知っておきたくて。

では、早速。

EnclosedとTheoriesは併用できる。外部クラスEnclosingTheoryをJUnit実行すれば、内部クラスEnclosedTheoryがJUnit実行される。これでTheoriesを使いたいけれど、テストクラスを分けたくない場合は大丈夫。
@RunWith(Enclosed.class)
public class EnclosingTheory {
    @RunWith(Theories.class)
    public static class EnclosedTheory {
        @Theory
        public void testTheory(Fixture f) throws Exception {
            // test method.
        }
    }
}

EnclosedとCategoriesは併用できない。外部クラスEnclosingTheoryにカテゴリOuterを付けて、Categoriesを使ったテストスイートを実行しても、テストが見つからない。
@RunWith(Enclosed.class)
@Category(Outer.class)
public class EnclosingTheory {
    @RunWith(Theories.class)
    public static class EnclosedTheory {
        @Theory
        public void testTheory(Fixture f) throws Exception {
            // test method.
        }
    }
}
@RunWith(Categories.class)
@IncludeCategory(Outer.class)
@SuiteClasses(EnclosingTheory.class)
public class CategorizedTestSuite {
    // NoTestsRemainException is thrown.
}

ただ、内部クラスEnclosedTheoryを直接指定すれば、実行させられる。Enclosedの甲斐がないと見るか、互いに独立した分類が使えると見るか、悩ましい。
@RunWith(Enclosed.class)
public class EnclosingTheory {
    @RunWith(Theories.class)
    @Category(Inner.class)
    public static class EnclosedTheory {
        @Theory
        public void testTheory(Fixture f) throws Exception {
            // test method.
        }
    }
}
@RunWith(Categories.class)
@IncludeCategory(Inner.class)
@SuiteClasses(EnclosedTheory.class)
public class CategorizedTestSuite {
    // run testTheory.
}

上記でテストが実行されるので、CategoriesとTheoriesは併用できることが分かる。

調べて見ると、CategoriesとEnclosedはそれぞれSuiteのサブクラスだった。併用できないのもさもありなん。

以下は、調べながら考えたことをつらつらと。

こうして調べて見ると、Categoryアノテーションで並列化のための分類をするのは筋が悪い気がしてきた。MECEに分割したいのだけれど、アノテーションの付け忘れやテストスイートへの追加忘れがありそう。何並列にするかによるけれど、上位のパッケージ構成でざっくり割っちゃった方が安全かなぁ。

CIとの相性も考える必要がある。AntのJUnitタスクから実行するなら、パッケージ構成やファイル命名規約に加えてFileSetで色々できる(開発端末上では使えないけれど)。一方、MavenはCategoryにも対応している。そろそろAntから卒業した方がいい気がしてきた……。

なお、調べるために書いたコードはso-c/junit4.12-categories-configuration-sampleにアップしてある。ここに書いたスニペットよりゴチャゴチャしているけれど、ちゃんと動くのでこれはこれで。

2015年8月1日土曜日

GitHubにPJを作成し、Eclipse (EGit) でCloneし、Mavenプロジェクトにする

EclipseプロジェクトをEGitでGitHubにPushするの手順がいまいち使いにくかったので、EclipseをMarsにしてMavenを使ったやり方を整理してみた。まだ気になるところはあるけれど、一旦こんなところで。

GitHub上にリポジトリを作る

GitHubにログインして、右上の"+"メニューから"New Repository"を選び、リポジトリ作成画面を表示させる。必要な項目を入力して、"Create repository"ボタンを押すと、リポジトリが作られる。

入力内容によってREADME.mdなんかが出来たり出来なかったりするけれど、この投稿はファイルができているケースを想定して続ける。

Eclipseとリポジトリを連携する

httpsプロトコルで連携する。sshでも連携できるけれど、その場合は事前に公開鍵を作成しGitHubに登録しておく必要がある。

Windows > Show View > Git Repositoryを選び、そのビューを表示させる。"Clone a Git Repository"を選び、Location > URIにGitHubリポジトリの"HTTPS Clone URL"を入力する(リポジトリ初期表示時はHTTPSではなくSSHなので、HTTPSリンクを押して切り変える)。Hostなどが自動的に埋められるので、AuthenticationにGitHubのユーザとパスワードを入力し、"Next"ボタンを押す。Local Destinationを選んでFinishを押すと、そこにリポジトリのCloneができる。

リポジトリからEclipseにプロジェクトをimportする

EclipseのGit Repositoryビューで、リポジトリを右クリックして、"Import Projects"を選ぶ。"Import as general project"を選んで、"Next"ボタン、"Finish"ボタンを順に押していくとimportされる。

general projectを選んでいるのは、リポジトリを作成するときにファイルが作られているから。こうしてからこの後にMavenプロジェクトにするのと、完全に空にしておいてこの時に新しいMavenプロジェクトとして作成するのとどちらがベターなんだろう。

ここで.gitignoreにgitignore/Global/Eclipse.gitignoreを追加しておくと後から誤コミットをしなくて済む。.classpathなどなくてもこの後Maven化するので問題ない。

インポートしたプロジェクトをMavenプロジェクトにする

importしたプロジェクトを右クリックして、Configure > Convert to Maven Projectを選ぶ。

J2SEに関するWarining "Build path specifies execution environment J2SE-1.5. There are no JREs installed in the workspace that are strictly compatible with this environment."が出る。pom.xmlに下記を追記して、Maven > Update Projectで解消すいる(参考:Maven Project を作成すると警告が出る - 電卓片手に)。
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.3.2</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
      </configuration>
    </plugin>
  </plugins>
</build>

Mavenで依存するライブラリを追加する

右クリックして Maven > Add Dependenciesを選び、からライブラリを検索して追加すると、Maven Dependenciesに追加される。

あとは

好きなようにコードを書けばOK。ただし、Mavenのarchitypeを使っていないので、ソースフォルダなどは手で作らないといけない。GitHubのリポジトリは空にして、新しいプロジェクトを作ってimportすればarchitype使えそうだけれどどちらが楽だろうか。

参考

2015年2月18日水曜日

継続的テスト、継続的インテグレーション、継続的デリバリー

最近、テストとビルドの関係について考え直している。『継続的デリバリー』を読み始めて少しだけまとまってきたので、整理を兼ねてメモしておく。

結論から言うと、テストとビルドの結合はこれまで考えていたよりずっと密だった。継続的インテグレーション/継続的デリバリーは継続的テストを含んでいる。スピードを上げるには〈デプロイメント・パイプライン〉を実装する必要がある。

なお〈デプロイメント・パイプライン〉は『継続的デリバリー』の中核となるパターンで、今のところ、インスペクション、コンパイル、ユニットテスト、ビルド、デプロイ、インテグレーションテスト、システムテスト、リリースなど一連のプロセスをうまく組み合わせることだと理解している。

ただ、組み合わせる範囲が広過ぎて、どこからどう手を付けたらいいのやら。『継続的デリバリー』の続きにヒントがあると期待しているのだけれど。

さて、以降はこの考えに至るまでに考えたあれやこれや。

テストとビルドは切っても切り離せない。そもそも正しい構成のテストがテスト環境にデプロイされていないと、テストする意味が無い。『ソフトウェアテスト 293の鉄則』でも、ビルドに関する鉄則が出てくる。
鉄則170 ビルドスケジュールを調整せよ
鉄則171 ビルド引き渡し前のプログラマの仕事を把握せよ
鉄則172 ビルドの受け入れ準備は怠るな
鉄則173 ときにはビルドのテスト受け入れを拒否することも大切だ
鉄則174 まずはスモークテストで判断せよ

一方で、テスターがビルドしているイメージはない。ビルドしてデプロイするのは別の役割に思える。テスターがするとしても全員ではないだろう。テストレベルが上がれば、テスターの人数が試験環境数を上回る。

〈テスト自動化〉と言ったときも、ビルドの自動化までは想像しないことが多いと思う。Javaでよく使うツールでいうとJUnitやSeleniumとかが真っ先に思い浮かんで、Antやmavenまではなかなか辿り着かない。

そのせいか、〈継続的インテグレーション〉とか〈継続的デリバリー〉と聞くと、ビルドやデプロイのことが真っ先に思い浮かんで、今度はテストがなおざりになる。

でも〈継続的インテグレーション〉について改めて『継続的インテグレーション入門』を読み返したりしてみると、テスティングやインスペクションまで含んでいる。継続的インテグレーションのベストプラクティスにも、Make the build self-testingが並んでいる。正しくビルドできたことを、テストで確認する必要があるからだと思う。

つまり、テストから見ても、ビルドから見ても、お互いに強く必要としあっている。

という論理的な帰結は論理的な帰結として、実際的な問題としてインスペクションしてコンパイルしてユニットテストしてビルドして、データベースにデータ準備して実行環境を構築して、そこにデプロイしてインテグレーションテストやシステムテストしてリリースしようなんて、膨大なスキルセットを持つユニコーンか、せめてそれぞれのエキスパートと全体を見渡すアーキテクト的なリーダを務められる人が集まらなきゃできない。

それぞれどれも大変なのに、一貫した効率的なデプロイメント・パイプラインなんて、どうしたらうまく実装できるんだろうか。

References

2014年7月30日水曜日

テストピラミッド

テスト戦略やテストアプローチについて調べていたら、テストピラミッドというコンセプトに行き当たった。自分の考えを整理するのにも、他人に考えを伝えるのにも使えそうなのでメモしておく。

考えたのはMike Cohnという人。見覚えがあると思ったら、『アジャイルな見積りと計画づくり』の著者だった。初出は書籍"Suceeding with Agile"。まだ読めていないけれど、Martin FowlerのTestPyramidをとっかかりに調べて分かった範囲で書く。

要は、「Unit test > Subcutaneous Test (サービス層のテスト) > End-to-end test」とピラミッド状になるようにしろよという話。

メソッドを直接叩ける高速で柔軟なUnit testじゃないと、ビジネスロジックの複雑な組み合わせをテストしきれない。GUI操作を経由する低速で融通が利かない (≒目的のテストを書き辛い) End-to-endテストでは、効率が悪すぎる。Unit testの必要性については、アジャイル開発において、技術と品質の重要性は不可欠だ(後編)。Agile Japan 2013 - Publickeyに詳しい。

将来、End-to-endテストも高速になるだろうし、融通が利かないという見方には「レコーディングツールを使えば簡単にテストを書ける」という反論が考えられるけれど、Recordedテストは壊れやすく、壊れてしまったら再レコーディングするハメになる。「レコーディングツールで最初は簡単にテストを書けるという特徴」は、Ice Cream Cornというアンチパターンを招きがちという意味で、危険でさえある。なお、テストの維持コストやRecorded Testの問題については、"xUnit Test Patterns"が詳しい。その上、仮に、End-to-endテストが高速になって、保守性の高いテストを書けたとしても、Non-determinism problemsがあると言っている。

各テストレベルのテスト目的は異なるはずなので、各テストレベルのバランスの取れたテスト戦略・テストアプローチ(Test portfolio) を取るのが健全だと言っている。(少なくとも最初は)簡単だからという理由でEnd-to-endテストの代わりに、Martin FowlerはSubcutaneous test (ユーザーインターフェースのすぐ下から操作するテスト)を推奨している。RESTインタフェースを備えたWebアプリケーションの場合、ブラウザを操作してフォームに入力してパラメータを組み立てる代わりに、REST APIを叩くイメージだろうか。テストコード中でこれを使えば、End-to-endテストのテスト目的 (Test Object) をほぼ満たしつつ、UIに起因する問題を回避できるとしている。

高レベルテストは第二防衛ラインなので、もし失敗したらプロダクトコードを直すだけでなく、ユニットテストを追加すべきだと言っている。

2014年4月2日水曜日

UbuntuへのRのインストール

Ubuntu 13.10にR3.0.3とRStudioをインストールした時の手順を残しておく。

CRANのインストール手順に従って、Rをインストールする。

まず/etc/apt/sources.list に下記のような1行を追記して、リポジトリを追加する。
deb http://<my.favorite.cran.mirror>/bin/linux/ubuntu saucy/

ただし、<my.favorite.cran.mirror>はをミラーサイト一覧参照して適当なミラーサイトに置き換える。

また、末尾の(saucy/)はUbuntuのバージョンに合わせたコードネームに書き換える。コードネームは下記コマンドで確認できる。
cat /etc/lsb-release

例えば、筑波のミラーからUbuntu 13.10 (saucy)にインストールする場合、次の様になる。
deb http://cran.md.tsukuba.ac.jp/bin/linux/ubuntu saucy/

リポジトリへのアクセスに必要な公開鍵を取得する。
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9

リポジトリからRをインストールする。
sudo apt-get update
sudo apt-get install r-base

インストール確認。次のコマンドでRが起動したらOK。
R

続けて、推奨Rパッケージもインストールしておく。
sudo apt-get install r-cran-*

References

2013年12月9日月曜日

Javaのアサーション (assert文) の使いどころ

Javaのアサーションについて、少し調べたことをメモしておく。『言語設計者が考えること』の「12章 Java」で、Javaプログラマへの助言として
assert文を至る所に散りばめること
なんて書かれていたけれど、使いどころがよく分らなかったのが、調べたキッカケ。

アサーションを使用したプログラミング (Java言語仕様) によると、使いどころは次の3つ。リンク先には具体例がもあるので、これを見るとおおよその想像がつく。
  • 内部の不変条件
  • 制御フローの不変条件
  • 事前条件、事後条件、およびクラスの不変条件

この内、3つ目の「事前条件、事後条件、およびクラスの不変条件」のさらに「事前条件」には「publicメソッドの引数チェックに使ってはいけない」という但し書きが付く。publicメソッドの引数が満たすべき事前条件はAPI仕様の一部だというのがその理由。『Java セキュアコーディングスタンダード 』の「MET01-J. メソッドの引数の検証にassertを使わない」に詳しい。
アサーションは、public メソッド内の引数チェックに使用しないでください。

引数のチェックは通常、メソッドの仕様 (または規約) の一部になっており、アサーションの有効/無効にかかわらず、この仕様に準拠する必要があります。アサーションを使用して引数をチェックした場合、不正な引数によってランタイム例外 (IllegalArgumentException、IndexOutOfBoundsException、NullPointerException など) が発生する可能性があります。アサーションが失敗しても、適切な例外はスローされません。

「適切な例外をスローする」とあるけれど、例外は使わないで通常の制御フローを前提にアサーションを使うのか、それともアサーション以外の例外を使うのか、一般解は存在しない。例外設計における大罪や『Effective Java 2nd Edition』の「項目57: 例外的状態にだけ 例外を使用する」が参考にはなるけれど、最後は作ろうとしているソフトウェアがどう振る舞うべきか、自分で考えるしかなさそう。

というわけで、指針は掴めたけれど、簡単な話ではない。

References

2013年11月26日火曜日

FindBugsのDetector Pluginチュートリアルをやってみた

FindBugsのDetectorPluginTutorialを試してみたときのメモ。FindBugs Eclipse Pluginへの追加を想定している。使用したバージョンは次の通り。
  • Eclipse 4.2
  • FindBugs 2.0.2
以下、見出しごとに躓いたポイントをメモしておく。



Creating Our Plugin


Setting Up Eclipse

素直にそのままやって問題なかった。

Setting Up the Classpath

findbugs.jar, bcel.jarに加えて、jsr305.jarもClasspathに追加する必要があった。findbugs.jarが依存しているみたい。

Writing the Bug Detector

そのままDetector codeのサンプルをコピーして問題なかった。

Deployment & Testing

Building

以下2つのxmlファイルは、プロジェクトフォルダーのルートに配置する。書かれている通りだけれど、読み落としがち。

findbugs.xml

コメントにあるとおり、公式サイトと要素名が異なるけれど、こちらの記載通りFindBugsPlugin要素で問題なかった。

サンプルには含まれていないけれど、一行目にXML宣言を追加しておく方がベターだと思う。

messages.xml

そのままサンプルをコピーして問題なかった。

Building in Eclipse

そのままやれば問題ないのだけれど、JAR Exportの設定が色々と初期値と異なる点に注意。間違えるとプラグインとして追加しても、Invalidと表示されて機能しない。一度やれば、jardescからその設定で再ビルドできる。

CIするためにAntタスクとして定義したい。

Loading Our Plugin

GUI (Eclipseの設定画面 Java > FindBugs) から追加した。EclipseのpluginsフォルダのFindBugsのpluginフォルダに追加しても、うまくいくかも試したい。


ここまでやって、Quizのコードスニペットを含むクラスでFindBugsを実行してみたら、期待通り動作した。めでたし、めでたし。

以下は、覚え書き。

このチュートリアルの"Debugging"はまだ書かれていない。テストケースの簡単な説明はFindbugsTestCasesにあるけれど、ここを読むだけではちょっと分りそうにない。実際のテストケースを見ながら、試行錯誤が要りそう。

チュートリアルではなぜこうするのか分らないけれど、Plugins4FindBugsで補完できる。Detector Pluginの概要が記載されている。

Eclipse Pluginに特化した内容として、コメントでFindBugs In Eclipse Tutorialが紹介されているのに、後から気がついた。ただ、FindBugs 1.3.9よちょっと情報が古い。

References

2013年8月21日水曜日

Javaのデコンパイラと難読化ツール

Javaのクラスファイルをデコンパイルしたソースコードは読みやすいと聞いて、「どれくらいソースを再現できるのか?」と「難読化したらどれくらいデコンパイル結果が読み辛くなるのか?」について試してみたくなった。というわけで、まずはデコンパイラ (decompiler) と難読化ツール (obfuscator) ついて調べてみた。今回はツールの調査だけで、実行方法についてはおいおい。なお、調査方法は、GoogleとStack Overflow頼み。

デコンパイラはJava Decompilerでいいのかな。デコンパイラとして真っ先に思い浮かんだJADは、更新が止まっていた。Java DecompilerもEclipseプラグイン・JD-Eclipseが最近のEclipseだと動かないようだけれど、少なくとも、Mchr3k - JDEclipse-Realignというフォークがメンテナンスされている。
Java Decompiler (Yet another Fast Java decompiler) has:
  • explicit support for decompiling and analyzing Java 5+ “.class” files.
  • a nice GUI:
decompiler - How do I "decompile" Java class files? - Stack Overflow
ともあれ、こちらはすんなり使えた。クラスファイルからほぼソースそのままにデコンパイルできてビックリ。Live Demoもある。

難読化はProGuardが良さそう。予備知識が無いので手探りだけれど。こちらは現在もアクティブな様子。最近はAndroidアプリの難読化に力を入れているよう。
Well, you can find here a list. ProGuard is pretty good. I've used it myself, but only to "minify" Java code.
obfuscation - Best Java obfuscator? - Stack Overflow
ただ、こちらは簡単には使えなさそう。設定が必要そう。幸い公式サイトのマニュアルが充実しているようなので、それを見ながらもう少し調べよう。

ところで、難読化すると、クラスやメソッドなどの名前が変わるから、リフレクションAPIを使っていると実行時例外が送出される。けれど、ProGuardのIntroduction > Reflectionによると、典型的なリフレクションAPIに対応しているみたい。

References

2013年8月3日土曜日

Out parameter, collecting parameter, visitor pattern

『Effective Java (第二版)』の「項目15 可変性を最小限にする」では不変オブジェクト (Immutable object) を推奨している。これは状態を持たないから、シンプルに扱える。反対に状態を持つ可変オブジェクト (Mutable object) は、扱いに気を遣う。扱おうとしているときにどういう状態なのか意識しないといけない。状態に起因したバグがあったら、最悪、状態が変更されている場所を全て確認しないといけない。

これに真っ向から対立しているのが、Out parameter。状態を変えるために渡す可変オブジェクトのことを指す。Webを検索してみると、アンチパターンとして紹介されている記事が見つかる。

でも、"Collectiong parameter"として『実装パターン』や『パターン指向リファクタリング入門』で紹介されていたりする。また、『パターン指向リファクタリング入門』では、その延長線上に"Visitor Pattern"を適用したパターンも紹介されている。

確かにこちらの方が合理的なケースもありそう。でも、基本的にはあまり使わない方がよさそう。コマンドとクエリは分離するのが原則だ。使うなら、Javadocに明記するなりしないと混乱を呼びそう。C#のoutキーワードに相当するものがJavaにはないから、引数の状態を変えるかどうか宣言だけから読み取れない。

ところで、out (C#)に使用例として「メソッドが複数の値を返すようにする場合に便利」だなんて書かれている。同時に扱いたい複数の値があるなら、クラスとしてまとめた方が読みやすくないだろうか。原則として、入力を与えたら戻り値が返ってくる関数として考えたい。

References

2013年7月6日土曜日

モンスターメソッドを解体する

『レガシーコード改善ガイド』の第22章「モンスターメソッドを変更する必要がありますが、テストを書くことができません」を自分なりに整理して、モンスターメソッドへの対処方法を要約してみる。

何をどこまでテストすれば?

まず、どういう種類のテストを書こうとしているか考える。それには、第13章「変更する必要がありますが、どんなテストを書けばよいのかわかりません」が役に立つ。そこでは、〈仕様化テスト〉と〈狙いを定めたテスト〉が紹介されている。〈狙いを定めたテスト〉を書くのが現実的だろう。モンスターメソッドの振る舞いは多様だから、いきなり全体を対象とした〈仕様化テスト〉は書けないことが多そう。

次に、モンスターメソッドを読み込んで、狙いを定める。どこまで狙いを絞り込めるかは、モンスターメソッドの作りと必要な変更によってケースバイケースになる。少なくとも自分にとっては、技芸の世界で、筋道立った説明をできない。

狙いが定まったら、検証方法を考える。この時、検証対象が一意に識別できなかったり (例: 別のブランチから同じ結果が返ってくる) 、テストから見えなかったりしたら、〈検出用変数〉または〈クエリメソッド〉を導入する。この時点では、これ以上の編集は避けた方が無難だと思う。やり過ぎると〈編集して祈る〉のと変わらない。

テストを書く

ここまでで、何のためにどの範囲でどんな検証をしないといけないか、具体的になってくるはず。ここまで来たら、テストを書き始める。書き始めたはいいが、モンスターメソッドを持っているクラスをインスタンス化できなかったり、モンスターメソッドの引数をインスタンス化できなかったりすることが多いと思う。その場合は、別の章を参照して対処する (ここでは深入りしない)。
  • 第09章 このクラスをテストハーネスに入れることができません
  • 第10章 このメソッドをテストハーネスで動かすことができません

変更とメソッド抽出

無事にテストが書けたら、実行してパスすることを確認する。この後、必要な変更を行うか、〈メソッドの抽出〉を行うかは、悩ましいところ。変更が局所的なら先に変更してもいいと思う。逆に変更がモンスターメソッドのあちこちに散らばるようなら、先にメソッドを抽出しておかないと後が苦しくなる。いずれにせよ、ここでは変更については触れずに、メソッドの抽出についてまとめる。

メソッドを抽出するときには、抽出後に残るメソッドの形を想像しておくと、どういう単位で抽出すればいいか方針を決めやすい。残る形には、〈骨組みメソッド〉と〈処理シーケンス〉の2種類がある。

〈骨組みメソッド〉は制御構造だけを持っていて、条件式や各条件下の処理はメソッドに任せてしまう。『実装パターン』だとConditionalに対応する。『デザインパターン』で例えるとFacadeやMediatorのイメージになる。

もう一つの〈処理シーケンス〉は単に順番にメソッドを呼び出していく。『リーダブル・コード』の無関係の下位問題の抽出を行うイメージ。「いちいちメソッドにするほどの問題ではないんじゃ?」と思っても、メソッドにして意図に即した名前を付けておくとリーダビリティが上がるはず (『実装パターン』のExplaining Message)。

どちらが適しているかは、モンスターメソッドの元々の役割によって変わる。大抵の場合、モンスターメソッドは、実装コストが低いところに追加が集中した結果であって、最初からモンスターメソッドとして生まれたわけではない。処理の振り分けが役割だったなら骨組みメソッド、抽象度の高いAPI提供が目的だったなら処理シーケンスを残す方が自然だと思う。

どういう形を残す決めたら、メソッドを抽出する前に、抽出したメソッドのテストを書く。先にテストを書けばレガシーコードは生まれない。アジャイルじゃなくたって、TDDした方がいいと思う。

さらに分割

ここまで来たら、細かい粒度でテストできるようになっている。でも、モンスターメソッドを持っているオブジェクトは、得てしてGod Objectだったりする。抽出したメソッドを〈メソッドオブジェクト〉として取り出して、委譲するように修正することも考えていく。つまり、『レガシーコード改善ガイド』の〈メソッドオブジェクトの取り出し〉、『リファクタリング』のReplace Method with Method Objectを行う。

References


2013年5月18日土曜日

JavaScriptで依存性を排除するためにデフォルトパラメータを導入する

JavaScriptのクラスHogeをテストしたいのだけれど、次のような状況でそもそもインスタンス化が大変な場合にどうするか? という話。
  • Hogeはコンストラクタ内で別のクラスFugaをインスタンス化してプロパティに設定している。
  • Fugaはインスタンス化の際にサードパーティ・ライブラリのAPIを大量に呼び出している。
  • サードパーティ・ライブラリは、開発環境では使えない(例えば、REST APIを提供するサーバがまだ立っていない)。
この場合をコード例で表してみる。サードパーティ・ライブラリが使えないため、Fugaのコンストラクタ呼び出しでエラーが発生し、Hogeをインスタンス化できないとする。
Hoge = function () {
  this.fuga = new Fuga();
  // ...
}
// ...
Fuga = function () {
  this.thirdPartyLibrary = new ThirdPartyLibrary();
  // ...
}
// ...

FugaがThirdPartyLibraryをラップしているから、テスト時にはテストダブルに入れ替えたい。でも、そもそもHogeもFugaもインスタンス化できない。

こんな状況に対応するためのリファクタリングとして、『レガシーコード改善ガイド』は25.14「コンストラクタのパラメータ化」か、デフォルト引数の追加を紹介している。オーバーロードのないJavaScriptでは、コンストラクタをパラメータ化できないので、デフォルト・パラメータを指定する。

デフォルト・パラメータがtrueと見なせる(false、null、0、""、undefinedのいずれでもない)なら、こんな風に短く書ける。||は真偽値ではなくてfugaを返す性質を利用している。
Hoge = function (fuga) {
  this.fuga = fuga || new Fuga();
  // ...
}
// ...

もっとロバストな書き方は次の通り。こちらは、デフォルト・パラメータがfalseと見なされる場合も使える。実用的なのは、デフォルト値が0やfalseの時。
Hoge = function (fuga) {
  if (typeof fuga === 'undefined') {
    fuga = new Fuga();
  }
  this.fuga = fuga;
  // ...
}
// ...

References



JavaScriptにおける検出用変数

JavaScriptで『レガシーコード改善ガイド』の第22章「モンスターメソッドを変更する必要がありますが、テストを書くことができません」で紹介されている「検出用変数の導入」を行ってみる。

『レガシーコード改善ガイド』のサンプルコードはJavaだからインスタンス変数として導入しているけれど、ここでは関数プロパティとして導入する。JavaScriptでは、関数もオブジェクトだからプロパティを持つことができる。

関数プロパティとして導入した方が、使用する場所に近くなるから読みやすくなるし、何かの拍子に誤ってアクセスする可能性が小さくなる。モンスターメソッドはただでさえ長い上に、そいつを持っているオブジェクトもゴッド・オブジェクトだったりするから、どれだけ慎重になってもなり過ぎるということはないはず。

というわけで、godObject.monsterMethodに検出変数isProcessedを導入してみる。これで複雑な条件をかいくぐって目的のブロックが実行されているかどうかを検出できるようになる(この実行が委譲されているなら、モックを使って検出できるけれど、モンスターメソッドが書かれるような状況では期待薄だと思う)。
var godObject = {
    monsterMethod : function (num) {
        // 検出用変数
        this.monsterMethod.isProcessed = false;
    
        if (true) {
            // ... 
            if (false)  {
                // ...
            } else if (true) {
                if (num === 2) {
                    this.monsterMethod.isProcessed = true;
                    // このブロックが実行されているかどうかを検出したい
                }
            } else {
                // ...
            }
        }
    }
}

検出用変数には、godObject.monsterMethod.isProcessedでアクセスできる。実際には、テストコード中でassertTrue(godObject.monsterMethod.isProcessed)のような形でアクセスすることになるだろうけれど、ここでは簡単に確認するためにconsole.logを使う。
godObject.monsterMethod(1);
console.log(godObject.monsterMethod.isProcessed); // > false
godObject.monsterMethod(2);
console.log(godObject.monsterMethod.isProcessed); // > true
godObject.monsterMethod(3);
console.log(godObject.monsterMethod.isProcessed); // > false

この方法は、『JavaScriptパターン』の4.3「関数プロパティによるメモ化パターン」を参考にしている。関数にその関数のキャッシュ変数を持たせられるなら、検出用変数を持たせられるだろう、と。

References


2013年5月13日月曜日

jgenhtmlでJsTestDriverのCoverageプラグインの出力をHTMLレポートに

JsTestDriverのCoverageプラグインは、LCOVフォーマットのファイルを出力する。「JsTestDriverでUnit Test + Code Coverage」では、Ubuntu上で実行していたからgenhtmlで簡単にHTMLレポートにできたけれど、Windows上ではgenhtmlを使えない。

Windows上でHTMLレポートに変換する方法について調べてみると、javascript - Viewing LCOV file in Windows - Stack Overflowにそのものズバリの質問が。回答を見てみると、Cygwinにgenhtmlをインストールする方法と、Java実装のjgenhtmlを使う方法があるらしい。

というわけで、今度はjgenhtmlを使ってみる。About JGenHtmlに書いてあるとおり、こちらを使うとパスの区切り文字("\"か"/"か) を気にしなくて良いし、JsTestDriverが動く (Javaがインストールされている) なら、jgenhtmlも動かせる。なお、動かしてみたjgenhtmlのバージョンは、1.5.0。

インストールも使い方も簡単。インストールは、jgenhtml-1.5.jar をダウンロードして、任意のフォルダに置けばよい。ここでは、「JsTestDriverでUnit Test + Code Coverage」のディレクトリ構成配下、test-lib/genhtmlに追加配置する。その時の使い方は、コマンドプロンプトで次のコマンドを実行する。
java -Dfile.encoding=UTF-8 -jar test-lib\jgenhtml\jgenhtml-1.5.jar -q -o test-output\coverage test-out\jsTestDriver.conf-coverage.dat
-Dfile.encodingの値は、JavaScriptファイルのエンコーディングに一致させること。そうしないと、HTMLレポートの日本語が文字化けする。jgenhtmlは、JVMのデフォルト・エンコーディングでJavaScriptファイルを読み込み、エンコードに関するオプションを持たないので、JVM側で指定している。エンコードにMS932以外を指定すると、今度はコマンドプロンプト上で文字化けするので、jgenhtmlのオプション-q(uiet)で、表示を止めている。

これで-o(utput)に指定したディレクトリにHTMLレポートが生成されるので、ブラウザで確認すれば良い。ただし、HTML5とCSS3を活用しているので、IEはサポート外とのこと。
The reports produced by jgenhtml use cutting edge HTML5 and CSS3 features.

If you are not using an extremely modern browser stuff probably won't work. If you use Internet Explorer my guess is you have no chance in anything before IE10.
BrowserSupport - jgenhtml - lcov genhtml tool ported to Java - Google Project Hosting
手元のIE9でざっと確認した範囲だと、IE8モードだとソースコードのハイライトを確認できるページがレイアウト崩れしている。

References

WindowsのコマンドプロンプトからJSHint

WindowsのコマンドプロンプトからJShintを実行する方法について書く。いちいちjshint.comのテキストエリアに貼り付けていては、リズムが悪いし、多数のファイルを一度にLintできない。

方法は次の2つが考えられたけれど、『メンテナブルJavaScript』に倣って、後者を選んだ。ざっと検索した感じ、Rhinoをインストールする方が、Nodeとnpmをインストールするより手軽そうだったのも理由の1つ(特にnpmのインストールには、GitとPythonが必要)。

Rhino bundleを使う場合のデメリットは、大きく2つ。前者は規定のオプションを渡すバッチファイルを書けば、代用できると思う。後者は替えが効かないので、将来対応されると嬉しい。
  • 設定ファイルを読み込めない。オプションはコマンドライン引数として渡さないといけない(ソースを直接いじるという荒技もできそう)。
  • コマンドラインフラグを使えない。コマンドラインフラグはNode版しか使えない。

まず、次の環境を構築する。Windows 7へのJava 7のインストールは済んでいるものとする。Rhinoは、Download RhinoからBinariesを、ダウンロードして任意のフォルダに展開すれば良い。JSHintは、Install — JSHintから、Rhino bundleをダウンロードして、任意のフォルダに保存すれば良い。以下、RhinoはRHINO_HOMEに、JSHintはJSHINT_HOMEにインストールしたとする。
  • OS: Windows 7
  • Rhino実行環境: Java 7
  • JSHint実行環境: Rhino 1.7R4
  • JShint (Rhino bundle): jshint-rhino-2.0.1.js

実行するには、次の形式でコマンドを実行すれば良い。-Dfile.encodingの値は、Lint対象のJavaScriptファイルのエンコーディングに一致させること。指定できるオプションについては、JSHint optionsを参照のこと。
java -Dfile.encoding=UTF-8 -jar RHINO_HOME\js.jar JSHINT_HOME\jshint-rhino-2.0.1.js [opt1=val1,opt2=val2,...] [global1=true,global2,global3,...] [list of files]
なお、オプションの書式は、jshint-rhino-2.0.1.jsの11000行目から始まる無名関数のコメントから抜粋。どうやら"="の有無でオプションかどうか判定している。以下はオプションの例。
camelcase=true,curly=true,eqeqeq=true,immed=true,indent=4,latedef=true,newcap=true,nonew=true,quotmark=single,strict=true,unused=true,undef=true,trailing=true,maxlen=80

References