android 使用分层架构企业应用(一)

背景:在用android开发企业应用的时候,发现按照传统的模式开发的代码结构比较差,业务逻辑处理与Activity是放在一起处理的,结构不清晰,类与类之间的耦合度较高,类的功能复杂,导致单元测试也很难开展;所以就有办法保证这个版本的稳定性,于是我跟我的团队都没有信心。因为我压根不知道程序什么时候会无缘无故报出一个bug,我总结一下原因是对过程缺乏必要的跟踪,导致业务行为模糊。我需要用敏捷管理的思想解决这些问题,所以我就开始重构了。

重构的目标:

  • 采用分层架构思想将类解耦,使类遵循单一职责原则。
  • 加入单元测试以保证过程跟踪。
  • 加入自动化构建工具并集成代码检查工具。
  • 加入持续集成输入单元测试结果及代码覆盖率。

具体实现:

将业务逻辑处理单独分离出来,并与Context分离,使其成为与android无关的可独立运行的类如:

SessionManagerService.java

public interface SessionManagerService {
	// 用户登录
	public String login(User user)throws RequestError;
}

就这么一个接口它的职责非常单一,就提供一个登录操作的方法。

关于这个接口的实现类代码就不贴了,实现了这个接口后就可以用单元测试对这个方法进行验证。

SessionManagerServiceTest.java

public class SessionManagerServiceTest extends AndroidTestCase {

	private SessionManagerService sms;

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		sms = new SessionManagerServiceImpl();
	}

	/**
	 * 测试登录成功
	 * 
	 * @throws Exception
	 */
	@LargeTest
	public void testLoginSuccess() throws Exception {
		User user = new User();
		user.setUserName("qnlpkuge");
		user.setPassword("111111");
		String result = sms.login(user);
		assertEquals("true", result);

	}

	/**
	 * 测试用户名不存在
	 * 
	 * @throws Exception
	 */
	@LargeTest
	public void testUserNotExist() throws Exception {
		User user = new User();
		user.setUserName("qnlpkugedfswe");
		user.setPassword("111111sdf");
		String result = sms.login(user);
		assertTrue(!"true".equals(result));
		assertTrue(result.contains("用户名或密码错误"));
	}

	/**
	 * 测试密码错误
	 * 
	 * @throws Exception
	 */
	@LargeTest
	public void testPasswordError() throws Exception {
		User user = new User();
		user.setUserName("qnlpkuge");
		user.setPassword("111111sdfa");
		String result = sms.login(user);
		assertTrue(!"true".equals(result));
		assertTrue(result.contains("密码错误"));
	}
         /**
	 * 异常测试
	 */
	public void testValidate() {
		try {
			User user = new User();
			user.setUserName("qnlpkuge");
			sms.login(user);
			fail("Should raise an RequestError");
		} catch (RequestError e) {
			assertEquals("用户名或密码不能为空!",e.getError());
			assertTrue(true);
		}
	}
}

由于android的单元测试只支持JUnit3,所以没有发使用起来没有注解那么方便,异常测试也显得麻烦。

单元测试通过之后就可以在Activity里面直接调用这个接口,让Activity的职责只需处理数据的显示上,当然还有针对Activity的单元测试。对业务逻辑层的测试属于功能集成测试,对Activity的测试属于界面测试,所以它们的测试方法会有很大区别。我在这里使用了第三方框架robotium,

LoginActivityTest.java

public class LoginActivityTest extends
		ActivityInstrumentationTestCase2<LoginActivity> {

	private Solo solo;

	public LoginActivityTest() {
		super("com.goosun.view", LoginActivity.class);
	}

	public void setUp() throws Exception {
		solo = new Solo(getInstrumentation(), getActivity());
	}

	public void testLogin() throws Exception {
		solo.clearEditText(0);
		solo.enterText(0, "admin");
		solo.clearEditText(1);
		solo.enterText(1, "admin");
		getActivity().runOnUiThread(new Runnable() {
			@Override
			public void run() {
				ImageButton btn = (ImageButton) getActivity().findViewById(
						com.tianque.seed.R.id.login_option);
				btn.requestFocus();
			}
		});
		solo.clickOnImageButton(0);
		Activity f = getInstrumentation().waitForMonitorWithTimeout(
		 getInstrumentation().addMonitor(MainGrid.class.getName(), null,
		 false), 9);
		 assertNotNull(f);
		assertEquals(getActivity().getString(R.string.main_grid), solo
				.getCurrentActivity().getTitle().toString());
		Assert.assertTrue(solo.searchText("泡妞管理系统"));
	}

	@Override
	public void tearDown() throws Exception {
		getActivity().finish();
	}

}

总体的思路就是这样,其他没有涉及太多android太多知识,只是构建一个高质量产品的开发方法学。

后续将继续讲在android开发中使用ant与持续集成。

相关推荐