android使用分層架構企業應用(一) – Android移動開發技術文章_手機開發 Android移動開發教學課程

背景:在用android開發企業應用的時候,發現按照傳統的模式開發的代碼結構比較差,業務邏輯處理與Activity是放在一起處理的,結構不清晰,類與類之間的耦合度較高,類的功能復雜,導致單元測試也很難開展;所以就有辦法保證這個版本的穩定性,於是我跟我的團隊都沒有信心。因為我壓根不知道程序什麼時候會無緣無故報出一個bug,我總結一下原因是對過程缺乏必要的跟蹤,導致業務行為模糊。我需要用敏捷管理的思想解決這些問題,所以我就開始重構瞭。

重構的目標:
采用分層架構思想將類解耦,使類遵循單一職責原則。
加入單元測試以保證過程跟蹤。
加入自動化構建工具並集成代碼檢查工具。
加入持續集成輸入單元測試結果及代碼覆蓋率。


具體實現:
將業務邏輯處理單獨分離出來,並與Context分離,使其成為與android無關的可獨立運行的類如:
SessionManagerService.java
Java代碼 
public interface SessionManagerService { 
    // 用戶登錄 
    public String login(User user)throws RequestError; 

就這麼一個接口它的職責非常單一,就提供一個登錄操作的方法。
關於這個接口的實現類代碼就不貼瞭,實現瞭這個接口後就可以用單元測試對這個方法進行驗證。
SessionManagerServiceTest.java
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
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(); 
    } 
 

作者“qnlpkuge”
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。