デブのDEV日記

港区で働くデブによるDEV(DEVELOPE)やデブ飯の記録。そんな美味いならデブになっても構わない。

Selenium WebDriverでInternetExploreDriverが遅い場合の対処法

テスト自動化ツールのSeleniumを現在のプロジェクトで導入しようと奮闘中。
Selenium自体は、以前使っていた事もあったのでハードルは高くないかなと思っていましたが
いくつかハマりポイントが。。
バージョンが変わったせいかな・・・

Selenium自動テストの流れは大体↓のような流れかと。

  1. FirefoxのアドオンSeleniumIDEをインストールする。
  2. SeleniumIDEを起動し記録を開始する。
  3. 画面操作を行い操作を記録する。(右上の赤いボタン)こうする事で操作内容がHTMLとして吐き出される。
  4. 画面操作が終わったら記録をストップする。
  5. このHTMLを流すだけで自動テストは可能。ただし、JenkinsなどのCIツールと連携して定期的な自動テストをしようとするとこの状態では不可能。
  6. Selenium公式サイトからDriverServerと各クライアントの言語のライブラリ群をダウンロードする。
  7. 自動テストする場合は、JAVAならJUnit等で実施する必要があります。なんとjUnitのコードはSelenium IDEから吐き出せます!
  8. 吐き出したコードは、メンテを考えてスパゲッティーコードにならないよう共通処理を基底クラスに移すなど整形した方が良いです。

細かい説明を大分端折りましたが、↑の流れで自動化可能です。

いざ、実食!!

自動テスト始まりましたがタイピングスピードおそ!!!
お前のパンチ、止まって見えるぜ!

ググってみたものの日本語のサイトに有用な情報なく、いつもの通りJonとかBobとかがいるサイトに行きつく。

Hi、Jack!

みたいなアメリカンな文章を眺めつつ、読んでいくと
Selenium Serverが64bitで俺も同じ問題にぶち当たったが、32bitにしたら解決したぜ!!ハハ!!」
みたいな文章が見つかる。
Thank you! Tom
おお、解消してるのか。
早速、64bitバージョンのSeleniumServerを32bit版に差し替え実行したところ無事解決。

とう訳で今日も美味いビールが飲もう。



SimpleDateFormatのYYYYとyyyyの違いに要注意

クライアントより連絡があり、本番環境である年月日表示が合わないと調査依頼があった。
画面とCSVで確かに生年月日が合っていない。。
CSV側がの西暦がずれている。
「2015/12/28」と表記されなければいけないものが「2016/12/28」と表示されている。
1年余分に年が進んでしまっているではないか!

調べてみたところ実装で怪しい箇所を見つけた。
SimpleDateFormatに指定している年のフォーマットが大文字の「YYYY」となっているではないか。

SimpleDateFormatのJavaDocを見ると

Y 暦週の基準年

と記載があった。この記載は、Java7以降からかな。
暦週の基準年ってなんやねん、っていう事でググってみました。

暦週の基準年は、WEEK_OF_YEAR のサイクルと同期がとられます。最初の週と最後の週の間にあるすべての週 (両端の週を含む) の暦週の基準年は、同じ値になります。したがって、暦週の基準年が同じでも、最初の日と最後の日では暦年の値が異なる場合があります。

たとえば、1998 年 1 月 1 日は木曜日です。getFirstDayOfWeek() が MONDAY で getMinimalDaysInFirstWeek() が 4 (ISO 8601 規格に準拠した設定) の場合、1998 年の第 1 週は 1997 年 12 月 29 日に始まり 1998 年 1 月 4 日で終わります。 暦年が 1997 年の最後の 3 日については、暦週の基準年が 1998 になります。 ただし、getFirstDayOfWeek() が SUNDAY の場合、1998 年の第 1 週は 1998 年 1 月 4 日に始まり 1998 年 1 月 10 日に終わります。1998 年の最初の 3 日間は 1997 年の第 53 週に入り、それらの日の暦週の基準年は 1997 です。

f:id:devdebu:20170516142501p:plain

↓ここ注目です。
暦年が 1997 年の最後の 3 日については、暦週の基準年が 1998 になります。

1997年でも年末の最後の3日は「YYYY」を指定すると1998年が返却される模様です。

以下のコードで検証してみました。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatterTest {

	public static void main(String[] args) throws ParseException {

		System.out.println("===== 2015年 ====================================");

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
		Date date = sdf.parse("2015/12/26");
		SimpleDateFormat sdf1 = new SimpleDateFormat("YYYY/MM/dd");
		String date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd");
		String date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		date = sdf.parse("2015/12/27");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		date = sdf.parse("2015/12/28");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		date = sdf.parse("2015/12/29");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		date = sdf.parse("2015/12/30");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		date = sdf.parse("2015/12/31");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		System.out.println("===== 2012年 ====================================");
		date = sdf.parse("2012/12/29");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);

		date = sdf.parse("2012/12/30");
		date1 = sdf1.format(date);
		System.out.println("YYYY→" + date1);

		date2 = sdf2.format(date);
		System.out.println("yyyy→" + date2);
		System.out.println("=================================================");

	}
}

実行結果

===== 2015年 ====================================
YYYY→2015/12/26
yyyy→2015/12/26
YYYY→2016/12/27
yyyy→2015/12/27
YYYY→2016/12/28
yyyy→2015/12/28
YYYY→2016/12/29
yyyy→2015/12/29
YYYY→2016/12/30
yyyy→2015/12/30
YYYY→2016/12/31
yyyy→2015/12/31
===== 2012年 ====================================
YYYY→2012/12/29
yyyy→2012/12/29
YYYY→2013/12/30
yyyy→2012/12/30
=================================================

2015年は、12/26まで正しく表示されていますが、12/27になると急に年がずれはじめてます。
2012年は、12/29まで正しく表示されていますが、12/30になると急に年がずれはじめてます。

YYYYを指定すると1月1日が所属する週にいる12月の日付に関して、+1年で年を返すようです。

年末年始返上になりかねない嫌がらせのような仕様です・・・

HTMLのサニタイズ処理(Spring)

サニタイズ処理をしてくれるメソッドがないかとApache Commonsを調べていたら
StringEscapeUtilsにそれらしきメソッドescapeHtmlを発見したやん!!

使ってみたところ、日本語もサニタイズされてしまうやん。。
サニタイズしたいのは<>&とかのこういうタグとかだけなので使えなかった。。。
commons langのバージョン3以降で escapeHtml4とかいうのがあったけど、これだけの為にcommonsのバージョン勝手に
あげられないのでSpringで探してみた。

お、あったやん!!
HtmlUtilsにhtmlEscapeなるメソッドを発見!!

HtmlUtils.htmlEscape(message.getMessage());

これで期待通りの動きをしてくれた。
めでたしめでたし。

【JAVA】固定長での文字列分割(split)

Stringクラスのsplitメソッドは、文字列分割で比較的よく使う。


  • 第2引数指定無しで分割する。

これはよく使う使い方ですね。

String str = "a,b,c,d,e";
String[] splits = str.split(",");
-- 実行結果:[a][b][c][d][e]
  • 第2引数を指定して分割する。

第2引数を指定すると分割の最大長を指定出来ます。
この例だと引数指定無しだと5分割されますが、第2引数に3を指定すると3分割されます。

String str = "a,b,c,d,e";
String[] splits = str.split(",", 3);
-- 実行結果:[a][b][c, d, e]

先頭から分割して第2引数の最大分割に達すると残りは全て最後の配列に格納されますね。

【JAVA】全角スペースでtrimする

Stringクラスのtrimメソッドは、半角スペースにしか対応していないので全角スペースもtrimしてくれるメソッドないかな、と探していました。
JAVA標準のAPIではまず無いだろうな、と思っていたので
とりあえずcommonsのStringUtilsを探してみました。
stripメソッド!発見しました。まさしく探し求めてたメソッド

第1引数:処理対象文字列
第2引数:trimする文字列

□実験コード

	String str = StringUtils.strip(" abc ", "  ");
	System.out.println("文字列 :" + str + "*+*+*");

	str = StringUtils.strip(" abc  ", "  ");
	System.out.println("文字列 :" + str + "*+*+*");

	str = StringUtils.strip(" a b c  ", "  ");
	System.out.println("文字列 :" + str + "*+*+*");

	str = StringUtils.strip("a     b c", "  ");
	System.out.println("文字列 :" + str + "*+*+*");

	str = StringUtils.strip("  a     b c ", "  ");
	System.out.println("文字列 :" + str + "*+*+*");

□実行結果

文字列 :abc*+*+*
文字列 :abc*+*+*
文字列 :a b c*+*+*
文字列 :a     b c*+*+*
文字列 :a     b c*+*+*

やるやん!!!

Mapの前方一致検索

今やっているシステムでCSVファイルでデータ連携される住所で1行で来る物がある。
システム上は、都道府県・住所1・住所2・住所3のように分割してカラムを保持しているので
1行で来る住所から都道府県を取り出して、システムのコード値に変換してやんないといけない。

Map<都道府県名, 都道府県コード>のようなMapオブジェクトをシステムで保持する事にして
ここから住所の先頭3文字を切り出して、都道府県コードを取得する処理を作成。

「神奈川県」のように4文字来る物もあるが、とりあえず3文字を切り出してMapから前方一致検索して取得する事にした。

	protected String getAreaNameByMap(Map<String, String> areaCodeMap, String areaPrefix) {
		for (String key : areaCodeMap.keySet()) {
			// キーを取得
			if (key != null) {
				if (key.startsWith(areaPrefix)) {
					return key;
				}
			}
		}
		return "";
	}

これで、Mapから前方一致した都道府県が返る。

JavaScriptにおけるコロン

JavaScriptのコードを見ているとよく意味が分からないコードが出てきたりします。

今回は、コードを見てたら以下のようなコロンのコードがあった。

io.sockets.emit("publish", {value: msg});


連想配列だと

var aaa = new Array('春', '夏', '秋', '冬')

こういう書き方しか知らなったけど、{value: msg}で生成出来るらしい。

まだまだ勉強不足です(;´Д`)

その他コロンは、三項演算子とラベルで使ったりするけど

JAVA勉強した時は、三項演算子は使うなと昔教えられました。

理由は、知らない人が多いから、、だって。

何かその辺の理由付けは感覚とかノリだよなぁ。

統計取ってる訳でもないし。

結構、開発現場の規約系は作った人の好みによるところも多くなりがち。

まぁ規約があるだけましですね。