MySQL クエリログを出力する

クエリログを出力する。いずれも設定はmy.cnfにて設定する。
MySQLのバージョンは5.6.19。
結合テスト環境でログ出力でき、ロールバック前のクエリがどこまで発行されているか確認することができた。

ログファイルに出力

[mysqld]
log=/var/log/mysql/query.log

うまくいかない場合(mysql再起動時にpidファイルが更新されてないエラーが出るなど)は下記テーブル出力を参照したい。

テーブルに出力

[mysqld]
general_log=on
log_output=TABLE

DBにログレコードが書き込まれるため、クエリが大量に発行される場合は注意が必要と思われる。

mysql > select * from mysql.general_log

※テーブルロックを解除しないとテーブル削除できない模様。

一時的にログを出力する

my.cnfに設定を書かなくてもクエリを流すだけでログ出力できる。

set global general_log="on";

ただし、設定として保存されるわけではないため、mysqlを再起動するともとに戻る。

mockito(2) 呼び出し回数チェック+例外処理チェック

mockito(1) スタブ的に使う - 基礎からのjavaの続き。
verifyメソッドで呼び出し回数のチェック。
例外を発生させ、キャッチした例外が想定通りかチェック。
(@Test(expected=XXX.class)では型のチェックしかできないのでキャッチしています)

あわせてテストケースに漏れがないか、カバレッジも確認したい。

UserLogicTest.java

続きを読む

クエリが飛んでるか確認

テスト環境にて、システムからクエリが発行されているか不明だったため、tcpdumpでパケットをキャプチャしてクエリがシステムから飛んできているか確認した。

手動実行したバッチ以外にクエリ発行するプログラムがいない環境だったため、DBサーバーで以下のコマンドを実行。

tcpdump port 3306

これでパケットが飛んできているかどうかは確認が可能。
ただし、パケットの中身は表示されない。
パケットの中身は「-X」オプションで確認できるが、ASCII文字として処理するらしいので、エンコードが必要だと思う。

送信元やLANインターフェースで切り分けをしたい場合、オプションを追加しないといけない。
「w」オプションでワイヤシャーク用のキャプチャファイルとして出力できる。

tomcat7 + struts2でwebアプリ(12) Ajax(1)

ボタンを押して時刻を取得するサンプル。
初回アクセスで時刻を表示して、ボタン押下時にjsonから取得したデータで時刻を更新する。
jsonの生成には、struts2jsonプラグインを使用。アクションをそのまま利用してjson作成できるのが便利。

(とりあえず時刻データはミリ秒データで受け取ってます)

続きを読む

mockito(1) スタブ的に使う

DAO依存のクラステストが面倒

テスト対象のクラスAがDAOクラスBに依存しているような場合、テストデータをDBにあらかじめ登録する必要がある。
dbunitのようなファイルからレコードを読み込むフレームワークはあるが、DAOではないクラスAのテストのためにレコードを仕込むのは面倒。

mockitoを使う

レコードをいちいち仕込むのは面倒なのでスタブを作成して、実際のメソッドをテストデータ呼び出しのメソッドに置き換える。
ここでmockitoフレームワークを使用する。

準備

今回はmavenを使用せず、手作業でライブラリを導入する。
公式から下記をダウンロード。

    1. mockito-core-2.0.29-beta.jar

mavenリポジトリにアクセスして、依存するライブラリをダウンロード。
依存関係にあるライブラリは「maven-metadata.xml」参照。

    1. byte-buddy-0.6.11.jar
    2. objenesis-2.1.jar

ビルドパスに外部jarとして追加。

実際に使ってみる

Userテーブルを操作するUserDaoとUserDaoを使用するUserLogicを用意。
ここではUserDaoをモックして、テストデータを返すようにした。
モックの作成方法、注入方法は複数あるが、下記以外はモックが注入されないなどうまくいかなかった。

続きを読む

dbunitのエラー

データベース処理テスト用のdbunitですが、エクセルからの読み込みがうまくいかずハマる。
ハマりポイントは以下の4つ。

データの間に空白があるとダメ

以下のように、空白のセルがあると「NullPointerException」となる。

no name age
1 tarou 20
2 (空) 20
3 hirosi 35

非表示項目は無視されない

エクセルの列を「非表示」にしても、dbunitからは読み込まれて処理対象となる。
適切な解決法があるかもしれないが、非表示にしていた列をエクセルから削除することで解決。

セルの書式設定に注意

日付は「文字列」書式で入力されていないと、うまく処理されない。
「TypeCastException」が発生して、処理が中断される。
また、数値も「文字列」でなければうまく処理されない場合がある模様。
例えば、「文字列」に設定していなかった列の値が指数表示となり、正しく比較(assert)できなかった。

空白セルに注意

見た目は全項目が空の行を処理対象として読み込み、「NullPointerException」となる。
ググってもほとんど情報がヒットしませんでしたが、「A1」のセルを選択した状態で「Ctrl+End」を押したときに空白のセルが選択される場合、選択されているあたりが空データを持つ行として扱われているようです。
(行の切り貼りをしていると発生する?)
とりあえず処理対象としたい範囲を選択し、新しく作成したシートに貼り付けて、書式を再設定することで正常に処理されるようになりました。


フレームワークのハウツーは情報少ないとつらいですね。

tomcat7 + struts2 でwebアプリ(11) メモ

アクション呼び出し前のFilterDispatcherあたりでNullPointerException

アクション呼び出し前の事前処理でNullPointerExceptionが発生し、
アクションのexecuteメソッドが呼び出されない問題。

基本的な設定やファイル名について確認しても解決しなかったので、
struts.xmlが配置されているフォルダが「Javaソースフォルダ」か確認したところ、
Eclipse上から「Javaソースフォルダ」として認識されていなかった。
新規作成で「Javaソースフォルダ」を作成し、そちらにstruts.xmlを移動したところ、
アクションが実行されるようになった。

indexからアクションへ自動遷移

<meta http-equiv="refresh" content="0;URL=<s:url action="ActionName"/>">

content直後の数値で遷移するまでの秒数を指定可能。

エラーページで例外のスタックを出力

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="contents/css/style.css" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>エラー</title>
</head>
<body>
<div class="contents">
	<div class="errorMessage">
		${exception.message}
		<div>
			${exceptionStack}
		</div>
	</div>
	<div>
		<a href="index.jsp">再読み込み</a>
	</div>
</div>
</body>
</html>

設定ファイル(.properties)の作成

下記リンクが詳しい。
http://struts.apache.org/docs/localization.html
http://www.mkyong.com/struts2/struts-2-resource-bundle-example/

アクション固有、パッケージ固有、グローバルの順番に設定ファイルを読みに行くようです。
今回のやり方であれば、struts.xmlに記述は不要。

指定パスのファイル一覧を取得

	public ArrayList<Path> createFileList(String path) throws Exception{
		ArrayList<Path> pathList = new  ArrayList<Path>();
		try(DirectoryStream<Path> ds = Files.newDirectoryStream(new File(path).toPath())){
			for(Path p : ds){
				pathList.add(p);
			}
		}
		return pathList;
	}

最終的にファイルとして扱うのであれば、いちいちPathに変換する必要はない気がします。