結論からいうと、Javaでは型定義はしっかりしましょうというお話です。
先日、私の本職の方でJavaを使用したシステム開発でちょっとした問題が起こりました。
単体テストでは動作していたプログラムが、結合テストでは動作しなくなる問題です。
上記自体はあるあるなので、環境設定や定義ファイルの変更を行い動かすことを試みたのですが、上手くゆかず・・・
原因を追ってみると作業者のローカルPCでJUnitを使用して単体テストした時は問題なくコンパイルされていたものが、jenkinsを使用してデプロイを行っている結合テスト環境では想定外のコンパイルがなされていました。
実際に、どういうことが起きていたのか。
【実装内容(例)】
StringBuilder sb = new StringBuilder();
Map map = new HashMap();
<中略>
sb.append(String.valueOf(map.get("KEY")));
フロント層とバック層に分かれた開発にありがちな、フロントで設定したbeanの情報をバックエンドのmapで受け取り文字列を組み立てる処理でした。
この実装で、どういうことが起きていたかというと・・・
【作業者のローカルPCで呼び出していたString.valueOfのメソッド】
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
【結合テスト環境で呼び出していたString.valueOfのメソッド】
public static String valueOf(char data[]) {
return new String(data);
}
なぜかまでの原因究明はできなかったのですが、結合テスト環境では想定していないメソッドが呼び出されていました。
改善するために下記のように型定義を行いました。
【修正後の実装内容(例)】
StringBuilder sb = new StringBuilder();
Map map = new HashMap();
<中略>
sb.append(String.valueOf((Object) map.get("KEY")));
型定義が重要なJavaという言語で、なんでも許容するObject型にキャストするということにかなりの抵抗感があったのですが、工数との兼ね合いもあり単純な解決策として採用しました。
もっと良い解決策はあったのかもしれませんが・・・
Javaでは型定義をしっかりしましょう。