Frisby.jsでHTTPのレスポンスヘッダの情報を取得する方法

REST APIのテストをFrisbyで自動化する - アシアルブログ」にHTTPのレスポンスボディの情報を取得する方法は書かれていたのだが、レスポンスヘッダの情報を取得する方法が書かれていなかったので、以下にメモしておく。


まず、上記ブログにもあるように、HTTPのレスポンスボディの情報を取得する方法は以下。

frisby.create('Test to get http body information.')
  .get('http://hoge.com/foo.json')
  .afterJSON(function(body) {
    frisby.create('Test to use use http body information.')
      .get('http://hoge.com/boo', {data: body})
      .... // do something.
      .toss();
  })
  .toss();


一方、HTTPのレスポンスヘッダの情報を取得する場合は以下のようになる(例はContent-Typeの情報を取得している)。
ポイントはafterJSON()の変わりにafter()を使う所。

frisby.create('Test to get http header information.')
  .get('http://hoge.com/foo.json')
  .after(function(err, res, body) {
    frisby.create('Test to use use http header information.')
      .get('http://hoge.com/boo', {contentType: res.headers['Content-Type']})
      .... // do something.
      .toss();
  })
  .toss();

Express入門をexpress 4.xで学ぶ場合のメモ

http://dotinstall.com/lessons/basic_expressjsはExpress 3.xが前提となっているのだが、Express 4.xで学ぶ場合には少し気をつけなければならない所があるので、以下にメモしておく。
【補足】
この記事を書いた時から更に変更が加わっているため、本記事のコメントも参考にして下さい。


http://dotinstall.com/lessons/basic_expressjs/26502
上記はexpressコマンドの使い方を学ぶ章であるが、Express 4.x以降はexpressコマンドのインストール方法が変わっているので注意が必要である。

$ sudo npm install express -g

演習では上記のコマンドを叩いているが、Express 4.x以降は以下のコマンドも実行する必要があった。

$ sudo npm install express-generator -g
$ node app

また、expressコマンドで作成したひな形アプリを起動するのに上記のコマンドを叩いているが、以下のコマンドに変更する必要がある。

$ npm start


http://dotinstall.com/lessons/basic_expressjs/26503
app.jsの内容を一部修正する必要がある。具体的には以下。

var express = require('express'),
    app = express();
 
// app.use(app.router); この行が不要になった
 
app.get('/', function(req, res) {
    res.send('hello world');
});
app.get('/about', function(req, res) {
    res.send('about this page!');
});
 
app.listen(3000);
console.log("server starting...");


http://dotinstall.com/lessons/basic_expressjs/26506
レッスンではmiddlewareが有効になるかどうかは、app.use(app.router)より前か後ろかで決まるとなっている。
しかし、Express 4.xではapp.use(app.router)の記載が不要になっているので、middlewareが有効になるかどうかはapp.get()より前か後ろかで決まる模様。


http://dotinstall.com/lessons/basic_expressjs/26507
ログ情報をターミナルに出力するmiddleware(logger)はexpressにバンドルされなくなったようなので、後継であるmorganを使う(GitHub - expressjs/morgan: HTTP request logger middleware for node.js)。具体的には、まず以下のコマンドでmorganをインストール。

$ npm install morgan

次にコードを以下のように変更する。

var express = require('express'),
    morgan = require('morgan'),
    app = express();
 
// middleware
// app.use(express.logger('dev'));
app.use(morgan());  // app.use(morgan('short')); 等とするとログの出力量を減らすことが出来る。

なお、Migrating from 3.x to 4.xによると、自分で作るmiddlewareはapp.get()やapp.post()より後ろに記載すべきとなっている。


http://dotinstall.com/lessons/basic_expressjs/26510
jsonとurlencodedの両middlewareもexpressにバンドルされていないので、後継であるbody-parserを使う。

$ npm install body-parser

コードは以下。

var express = require('express'),
    bodyParser = require('body-parser'),
    morgan = require('morgan'),
    app = express(),
    post = require('./routes/post');

// middleware
// app.use(express.json());
// app.use(express.urlencoded());
app.use(bodyParser());


http://dotinstall.com/lessons/basic_expressjs/26512
express.methodOverride()もexpressにバンドルされていないのでmethod-overrideもインストールする。

$ npm install method-override

コードは以下。

var express = require('express'),
    bodyParser = require('body-parser'),
    methodOverride = require('method-override'),
    morgan = require('morgan'),
    app = express(),
    post = require('./routes/post');

// middleware
// app.use(express.json());
// app.use(express.urlencoded());
// app.use(express.methodOverride());
app.use(bodyParser());
app.use(methodOverride());


http://dotinstall.com/lessons/basic_expressjs/26520
ここでも同様にexpress.cookieParser()、express.session({secret: '***********'})、express.csrf()が使えないので、それぞれcsurfexpress-sessioncookie-parserをインストールする。コードは割愛。


【参考資料】

GitHub + Travis CI + CoverallsでJavaプログラムのカバレッジ計測をする方法

Travis CICoverallsを使って、GitHubに公開しているJavaプログラムのカバレッジを測定する方法を以下に記載する(Mavenで管理されたJavaプロジェクトを想定)。

Travis CIとCoverallsの連携にはCoverallsの公式ページ(以下)で紹介されているcoveralls-maven-pluginを利用した。


ステップ1(事前準備)
GitHubTravis CIの連携は以下のサイト等を参考に実施しておく。

また、Coverallsのサイトにログインして、カバレッジ計測対象のGitHubリポジトリを有効化しておく。


ステップ2(pom.xmlの編集)
Javaプロジェクトのpom.xmlに以下を追加する。

<plugin>
    <groupId>org.eluder.coveralls</groupId>
    <artifactId>coveralls-maven-plugin</artifactId>
    <version>2.2.0</version>
</plugin>

GitHubのcoveralls-maven-pluginのREADMEを見ると、CoverallsのRepo Tokenも書いているが、GitHubの公開リポジトリを利用している場合には、記載してはダメのようだ。

次にpom.xmlに以下のような記載を追加することで、利用するカバレッジ測定ツールを指定する(以下はCoberturaの例)。JaCoCo等を使う場合にはcoveralls-maven-pluginのREAMMEを参照。

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <format>xml</format>
        <maxmem>256m</maxmem>
        <!-- aggregated reports for multi-module projects -->
        <aggregate>true</aggregate>
    </configuration>
</plugin>


ステップ3(.travis.ymlの編集)
GitHubTravis CI連携用に.travis.ymlファイルを作成していると思うが、その.travis.ymlに以下を追加する。

after_success:
  - mvn clean cobertura:cobertura coveralls:cobertura


以上で準備は完了。
GitHubソースコードをpushすると、自動的にTravis CIでビルドとテストが走り、その後テストデータがCoverallsに自動転送され、テストの統計データを見られるようになる。
CoverallsのプロジェクトページのTECHNICAL DETAILSにバッジが表示されているが、以下のようにカバレッジ率が表示されていれば(unknownじゃなくなっていれば)連携成功である。

ドットインストールのレッスン「ローカル開発環境の構築」の補足

「ローカル開発環境の構築」というレッスンで「#04 Webサーバーを導入しよう」というのがある。
ここでは、Webサーバをインストールした後に、Webブラウザでアクセスしてみて正しくインストール出来たかを確認しているのだが、レッスン通りにやっても上手くウェブページが表示出来なかった場合には、Linuxファイヤーウォールiptables)を停止してみよう。
具体的には以下のコマンドを実行する。

$ sudo service iptables stop


これでウェブページが表示出来るようになると思う。
あとは再起動後にiptablesが起動しないように、以下のコマンドを実行しておく(あくまでレッスン用の環境の場合です)。

$ sudo chkconfig iptables off

MockitoのArgumentMatcherの使い方

http://docs.mockito.googlecode.com/hg/latest/org/mockito/ArgumentMatcher.htmlを見ると、このクラスを使って以下のように、IsListOfTwoElementsクラスのような独自のArgument Matcherを作る事が出来る。

class IsListOfTwoElements extends ArgumentMatcher<List> {
    public boolean matches(Object list) {
        return ((List) list).size() == 2;
    }
}

List mock = mock(List.class);
when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
mock.addAll(Arrays.asList("one", "two"));
verify(mock).addAll(argThat(new IsListOfTwoElements()));


また、argThat(new IsListOfTwoElements())の所は、以下のようにメソッドにすると、可読性が高くなると書かれている。

verify(mock).addAll(argThat(new IsListOfTwoElements()));
//becomes
verify(mock).addAll(listOfTwoElements());


メソッドにするやり方は書かれていないが、以下のようにすれば良い。

class IsListOfTwoElements extends ArgumentMatcher<List> {
    public boolean matches(Object list) {
        return ((List) list).size() == 2;
    }
    public static List listOfTwoElements() {
        return argThat(new IsListOfTwoElements());
    }
}


ちなみにジェネリックを使うと以下のような感じか。

class IsListOfTwoElements extends ArgumentMatcher<List<String>> {
    @Override
    public boolean matches(Object list) {
        return ((List<?>) list).size() == 2;
    }	
    public static List<String> listOfTwoElements() {
        return argThat(new IsListOfTwoElements());
    }
}

@SuppressWarnings("unchecked")
List<String> mock = mock(List.class);
when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
mock.addAll(Arrays.asList("one", "two"));
verify(mock).addAll(listOfTwoElements());

System.out.printとかSystem.exitとかのユニットテストを補助してくれるルールを試してみる

System.out.printlnとかSystem.exitをテストするのはちょっと面倒なのだが、その辺りを補助してくれるJUnitのルールのコレクション(System Rules)があったので試してみた。


【事前準備】
System Rulesを使うにはApache Commons IOが必要という事でダウンロードしておく。


ユニットテストの例】
テスト対象クラスは以下のように標準出力や標準エラー出力に文字列を出力するメソッドやSystem.exit(0)を呼び出すメソッドがある。

public class MyClass {
    public void out() {
        System.out.print("Hoge");
    }	
    public void err() {
        System.err.print("Moge");
    }	
    public void exit() {
        System.exit(0);
    }	
}


上記のテスト対象クラスをSystem Rulesを使ってテストするコードは以下のようになる。かなりシンプルにテストコードが書けた。

public class MyClassTest {	
    @Rule
    public final StandardOutputStreamLog stdout = new StandardOutputStreamLog();	
    @Rule
    public final StandardErrorStreamLog stderr = new StandardErrorStreamLog();	
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();	

    MyClass sut;
    @Before
    public void setUp() throws Exception {
        sut = new MyClass();
    }
    @Test
    public void testOut() {
        sut.out();
        assertThat(stdout.getLog(), is("Hoge"));
    }
    @Test
    public void testErr() {
        sut.err();
        assertThat(stderr.getLog(), is("Moge"));
    }	
    @Test
    public void testExit() {
        exit.expectSystemExitWithStatus(0);
        sut.exit();
    }	
}


System Rulesは上記以外にも、システムプロパティのテストを補助するProvideSystemPropertyやセキュリティーマネージャのテストを補助するProvideSecurityManagerといったルールがあるようだ。


【関連記事】

MockitoのMatchers.anyObject()の使い方

MockitoのMatchers.anyObject()は以下のmethodA()のように、あるオブジェクトを引数に持つメソッドが呼び出されたかどうかを、Mockitoで検証する際等に使うことが出来る。

public class MyClass {
    
    private MyField field;
    	
    public void setField(MyField field) {
        this.field = field;
    }
    
    public void methodA(String text) {
        field.methodB(new MyObject(text));
    }
}


具体的な検証コードは以下。

public class MyClassTest {

    MyField mock;
    MyClass sut;

    @Before
    public void setUp() throws Exception {
        mock = mock(MyField.class);
        sut = new MyClass();
        sut.setField(mock);
    }

    @Test
    public void testMethodA() {
        sut.methodA("test");
        // methodA()を呼び出すとその先でMyFieldのmethodB()が呼び出される事を検証
        verify(mock).methodB((MyObject)anyObject());
    }

}


なお、検証コードを以下のようにしても良さそうなのだが、実際にmethodB()が呼び出された際に渡されたオブジェクトと同一のインスタンスでは無いため、以下はエラーとなってしまう。このような場合にMatchers.anyObject()が使える。

verify(mock).methodB(new MyObject("test"));