massの日記

日々の薪

Android×TDD(model)

先日から取り組んでいたAndroidのTDD、modelのTestもかいてみた。
今回はActivityではないから、extendするTestClassは前回とは違う。
Contextの受け渡しはする予定だらAndroidTestCase。

それではまずは実装クラスから。
今回のmodelは図書館。市区町村名or緯度経度から図書館の一覧を取得する。
利用するAPIhttp://calil.jpから提供されているもの。

package jp.android.library.information.model;

//import 省略

public class LibraryUtil {
	private String libraryId = null;
	private String libraryName = null;
	private Double libraryLatitude = null;
	private Double libraryLongitude = null;
	private String libraryPlaceName1 = null;
	private String libraryPlaceName2 = null;
	
	public LibraryUtil(HashMap<String,String> hash) {
		setLibraryId(hash.get("systemid").toString());	
		setLibraryName(hash.get("systemname").toString());	
		setLibraryPlaceName1(hash.get("pref").toString());	
		setLibraryPlaceName2(hash.get("city").toString());
		String[] gecode = hash.get("geocode").split(",");
		setLibraryLatitude(Double.valueOf(gecode[1]));
		setLibraryLongitude(Double.valueOf(gecode[0]));
	}

	private void setLibraryId(String id) {
		libraryId =id;
	}

	private void setLibraryName(String name) {
		libraryName = name;
	}
	
	private void setLibraryPlaceName1(String place1) {
		libraryPlaceName1 = place1;
	}
	
	private void setLibraryPlaceName2(String place2) {
		libraryPlaceName2 = place2;
	}
	
	private void setLibraryLatitude(Double latitude) {
		libraryLatitude = latitude*1E6;
	}
	
	private void setLibraryLongitude(Double longitude) {
		libraryLongitude = longitude*1E6;
	}

	public String getLibraryId() {
		return libraryId;
	}
	
	public String getLibraryName() {
		return libraryName;
	}

	public String getLibraryPlaceName1() {
		return libraryPlaceName1;
	}

	public String getLibraryPlaceName2() {
		return libraryPlaceName2;
	}

	public Double getLibraryLatitude() {
		return libraryLatitude;
	}
	
	public Double getLibraryLongitude() {
		return libraryLongitude;
	}

	public static List<LibraryUtil> findLibraryByPlace(String place1, String place2) {                
            // 省略
        }
	
	public static List<LibraryUtil> nearbyLibraries(Double lat,Double lon) {
            // 省略
        }
	
	private static List<LibraryUtil> parseXml(XmlPullParser parser) throws XmlPullParserException, IOException {
            // 省略
        }
}


API利用部分は説明は割愛。
HTTPRequestを飛ばし、返されたXMLをparseして、LibraryUtilという図書館オブジェクトを作成する。
今回テストするのはHTTPの通信部分ではなく、図書館オブジェクトの生成部分。
意図したオブジェクトができているか確認するのがテストの目的。
前回のActivityとやっていることはほとんど同じ。あえてあげるなら、前回はassertの文法でNotNullというものしか使わなかったけど、今回は予測値と実態値が等しいか比較するassertEqualsを使ったこと。

package jp.android.library.information.test.model;

// import 省略

public class LibraryUtilTest extends AndroidTestCase {
	private LibraryUtil library = null;
	
	@Override
	protected void setUp() throws Exception {
    	LibraryUtil[] libraries = LibraryUtil.findLibraryByPlace(TestDefine.LIBRARY_PLACE1, TestDefine.LIBRARY_PLACE2);
    	library = libraries[0];
	}
	
	public void testGetLibraryId() throws Exception {
		assertEquals(TestDefine.LIBRARY_ID,library.getLibraryId());
	}
	
	public void testGetLibraryName() throws Exception {
		assertEquals(TestDefine.LIBRARY_NAME,library.getLibraryName());
	}

	public void testGetLibraryLatitude() throws Exception {
		assertEquals(TestDefine.LIBRARY_LATITUDE,library.getLibraryLatitude());
	}

	public void testGetLibraryLongitude() throws Exception {
		assertEquals(TestDefine.LIBRARY_LONGITUDE,library.getLibraryLongitude());
	}

	public void testGetLibraryPlaceName1() throws Exception {
		assertEquals(TestDefine.LIBRARY_PLACE1,library.getLibraryPlaceName1());
	}
	
	public void testGetLibraryPlaceName2() throws Exception {
		assertEquals(TestDefine.LIBRARY_PLACE2,library.getLibraryPlaceName2());
	}
}

まだ実行していないので、どこかにエラーがあるかもしれない。
ただ、テストがかけているから確認はさほど手間ではない。
モデルのテストが終われば、このモデルを呼び出す側ではモデルオブジェクトが間違っているといった心配はしなくてよい。
など、テストファーストでやった場合のメリットは後になるほど感じられると思う。
今回の開発サイクルは↓の形で進めた。

  1. アプリケーションプロジェクトで呼び出すクラスorメソッドを作成
  2. テストプロジェクトでテストクラスorテストメソッドを作成
  3. テスト実行
  4. NG
  5. 実装
  6. テスト実行
  7. OK

1でそのまま実装までしないよう踏みとどまるのが大事。