おしりんブログ

新人PGおしりんの色々まとめるよブログ

JUnitでログが出力されているかをテストする

こんばんよ~

すっかり日にちがあいてしまいました。
今週忙しくて…っていう甘え。

昨日は先輩達と夕飯食べてきたよ~
ざぼん美味しかったよざぼん。


あ。先週シルバーとってきました。
90はいったでしょとか思ってたけど83しか取れてなかった。

ぐやじい。


ということで、今日はJunitを使ってテストをする際、
ログが出力されているのかを確認(テスト)する方法
についてまとめたいと思うよ。


と、その前に、今回のプロジェクトでは
ログ生成ツールlogbackを使っていたんだけど、

logbacklog4jってなにが違うのかな~
と思って、少し調べてみた。


まず、Javaのロガーの構成(jar)を簡単にまとめるとこんな感じ。

・インターフェース
 →ログを出力するための機能一覧を提供している
  ・commons-logging
  ・slf4j
  
(上記インターフェースに対する)実装
 log4j
 logback
 java.util.logging
 
logbacklog4jの開発者が作った後継的な実装なんだって。

インターフェースに対する実装がしょぼいと、処理が遅かったり、
そもそもインターフェースに対する実装が未実装だったりするらしい。


ちなみに、今まではcommons-logging+log4jがトレンドだったらしいけど
最近はslf4j+logbackがトレンドらしい。


そうそう、で、結局log4jlogbackの違いはというと、
以下のような点でslf4j+logbackが優れているんだって。

1.ログ出力時のパフォーマンス向上
2.ログ設定を起動中に再読み込みする設定が可能
3.デバッグログ出力時、isDebugEnabledメソッドでの囲みが不要

(引用元:http://d.hatena.ne.jp/kimutansk/20121123/1353686394

調べながらへぇ~ってなってる。


ロガーの種類についてはこの辺にして、
いよいよ本題にうつっていくよ。

ログが出力されているのかを確認する方法」について。

って言ってもソースコードのっけるだけなんだけど…


log4jを使用してログを出力している場合

@Test
public void test() {
	StringWriter writer = new StringWriter();
	WriterAppender appender = new WriterAppender(new PatternLayout("%p, %m%n"),writer);
	LogManager.getRootLogger().addAppender(appender);
	LogManager.getRootLogger().setAdditivity(false);
	try{
		/** 何かしらのログを出力する処理 */

		/** エラーログのテスト */
		String logString = writer.toString();
		assertThat(logString, containsString(" 確認したいログメッセージ "));

	}finally{
		LogManager.getRootLogger().removeAppender(appender);
		LogManager.getRootLogger().setAdditivity(true);
	}
}


logbackを使用してログを出力している場合

@Test
public void test() {
	ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.clasLogger.ROOT_LOGGER_NAME);
	@SuppressWarnings("unchecked")
	final Appender<ILoggingEvent> mockAppender = mock(Appender.class);
	when(mockAppender.getName()).thenReturn("MOCK");
	root.addAppender(mockAppender);

	/** 何かしらのログを出力する処理 */

	verify(mockAppender).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
		@Override
		public boolean matches(Object argument) {
			return ((LoggingEvent)argument).getFormattedMessage().contains(" 確認したいログメッセージ ");
		}
	}));

こちらはMockito使ってますな。

ちなみに、
LoggerFactory.getLogger(ch.qos.logback.clasLogger.ROOT_LOGGER_NAME);
この部分、ロガーを指定しているんだけど、

rootロガーを使っていない場合は、
自分の使用しているロガー名を指定してあげないと動かない。

↓こっちじゃなくて

<root>
	<level value="WARN" />
	<appender-ref ref="system" />
</root>

↓こっち使ってる時とか

<logger name="trace" level="INFO" additivity="false">
	<appender-ref ref="trace.log" />
</logger>

ソースをなんとなくにしか理解せずコピ★ペした私は
自分がこの問題に引っかかっていることに気づかず、
小一時間程悩んでいました。
(先輩が一瞬で解決してくれました。)

ソースの引用元はhttp://qiita.com/sifueさんのQiita投稿記事。
ありがとうございました…


最後に雑談だけど、最近調べ物をしている時、
Stack OverFlowとかも見るようになったよ。

なんとなーく質問者の投稿記事見て、
自分と同じような問題でつまってる人見つけて、

回答者のソース見て「あーこんな感じか」とか思って
自分のコードに反映させてみたりして。

で、結果動いた時とかもう最高!
めっちゃ英語できた気分になる(そっち)


なんだかんだで毎日楽しく仕事してると思う今日このごろ。

ではでは。おやスヤァ