一、運用JUnit4 進行單元測試java
首先在工程的 src
文件夾內建立 test
和 test/java
文件夾。 android
打開工程的 build.gradle(Module:app)
文件,添加JUnit4依賴,點擊Gradle sync按鈕。json
build.gradle網絡
1 dependencies { 2 testCompile 'junit:junit:4.12' 3 }
(1)新建被測類:架構
1 public class Calculator { 2 3 public double sum(double a, double b){ 4 // 假設先返回結果0 5 return 0; 6 } 7 }
(2)新建測試類:app
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class CalculatorTest { private Calculator mCalculator; @Before public void setUp() throws Exception { mCalculator = new Calculator(); } @Test public void testSum() throws Exception { //斷言:1+1 = 2 assertEquals(mCalculator.sum(1d, 1d), 2d); } }
這時候 右鍵 - testSum()方法,選擇選擇Run > testRun , 也能夠經過命令行運行測試,在工程目錄內輸入:框架
1 ./gradlew test
這時測試由於我寫被測類的時候,返回的是0,因此跟指望的值不同,就會失敗。async
這時,咱們修改下Calculator.java的函數:ide
1 public double sum(double a, double b){ 2 return a + b; 3 }
保存,這時候再運行測試,成功,跟指望值同樣。函數
總結:位於src/tests
目錄下的測試是運行在本地電腦Java虛擬機上的單元測試。
編寫測試,實現功能使測試經過,而後再添加更多的測試,這種工做方式使快速迭代成爲可能,咱們稱之爲測試驅動開發。
二、使用Mockito等mocking框架來mock測試。
Mock:
mock對象就是在調試期間用來做爲真實對象的替代品。
mock測試就是在測試過程當中,對那些不容易構建的對象用一個虛擬對象來代替測試的方法就叫mock測試。
打開工程的 build.gradle(Module:app)
文件,添加Mockito依賴,點擊Gradle sync按鈕。
build.gradle
1 dependencies { 2 // 單元測試 3 testCompile 'org.mockito:mockito-all:2.0.2-beta' 4 testCompile 'junit:junit:4.12' 5 }
關於mokito的使用,官網已經給出很詳細了。我這裏主要想記錄下主要用到的。對於mvp架構下,測試presenter返回到view的數據,是否正確。
配合mvp模式下,利用本地json,模仿網絡請求,進行模擬數據,查看presenter 處理邏輯是否正確。
public class PresenterTest { @Mock Repository repository; // 網絡請求 @Mock View view; // view PresenterImpl presenter; @Before public void setUp() throws Exception { // 若是有使用到rxjava,能夠在這裏處理rxjava變成同步執行 MockitoAnnotations.initMocks(this); presenter = new PresenterImpl(view, repository); } @Test public void getOrderList() throws Exception{ String json = readAssetsJSON("get_list.json").optString("data"); List<ViewModel> list = JSON.parseArray(json, ViewModel.class); when(repository.getList(1)).thenReturn(Observable.just(list)); presenter.getList(1); ArgumentCaptor<ArrayList> captor = ArgumentCaptor.forClass(ArrayList.class); verify(presenter.getView()).onGetDataByFinish(captor.capture()); List<ViewModel> viewModels = captor.getValue(); assertEquals(list.size(), viewModels.size()); } }
get_list.json 是放到 src/test下的assets 目錄下,這個目錄在:打開工程的 build.gradle(Module:app)
文件,android節點下的sourceSets節點下,配置下:
1 sourceSets { 2 main { 3 ..... 4 } 5 6 test { 7 java.srcDirs = [ 'src/test/java'] 8 } 9 }
其餘的用法:參考下官方就行,由於官網是英文的,看不懂的,還能夠前往:Mockito 中文文檔
三、使用Robolectric
Robolectric 是一個針對於Android SDK 的單元測試框架,使用它能夠測試驅動你的Android應用程序的開發。測試用例只須要在JVM基礎上就能運行起來。
打開工程的 build.gradle(Module:app)
文件,添加Robolectric依賴,點擊Gradle sync按鈕。
build.gradle
1 dependencies { 2 // 單元測試 3 testCompile 'org.robolectric:robolectric:3.1-rc1' 4 testCompile 'org.mockito:mockito-all:2.0.2-beta' 5 testCompile 'junit:junit:4.12' 6 }
一、建立一個WelcomeActivity, 點擊登陸,跳轉到登陸頁面。
佈局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/btn_login"
android:text="click the btn" android:layout_width="wrap_content"
android:layout_height="wrap_content"/> </LinearLayout>
Activity:
public class WelcomeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.welcome_activity); final View button = findViewById(R.id.btn_login); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivity(new Intent(getContext(), LoginActivity.class)); } }); } }
測試的是:當用戶點擊登錄按鈕後,咱們啓動了正常的intent。
因爲Robolectric只是一個模擬的單元測試框架,LoginActivity並不會真正的啓動,可是咱們能夠檢查是否準確的發出了WelcomActivity的intent。
1 @RunWith(RobolectricTestRunner.class) 2 public class WelcomeActivityTest { 3 @Test 4 public void clickingLogin_shouldStartLoginActivity() { 5 WelcomeActivity activity = Robolectric.setupActivity(WelcomeActivity.class); 6 activity.findViewById(R.id.btn_login).performClick(); 7 Intent expectedIntent = new Intent(activity, WelcomeActivity.class); 8 assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(expectedIntent); 9 } 10 }
判斷點擊後textview 文本變化是否正常等:
1 @RunWith(RobolectricTestRunner.class) 2 public class WelcomeActivityTest { 3 4 @Test 5 public void clickLoginButton() throws Exception { 6 Activity activity = Robolectric.buildActivity(WelcomeActivity.class).create().get(); 7 8 Button btn_login = (Button) activity.findViewById(R.id.btn_login); 9 TextView tv_result = (TextView) activity.findViewById(R.id.tv_result); 10 11 btn_login.performClick(); 12 String resultsText = tv_result.getText().toString(); 13 assertThat(resultsText, equalTo("Click the login button")); 14 } 15 }
對於控制activity的生命週期,Robolectric 2.2版本之後增長了控制activity方法:
1 Activity activity = Robolectric.buildActivity(WelcomeActivity.class).create().get();
這會建立一個WelcomeActivity,而且已經調用了onCreate()。
(1)檢查一些在onCreate()和onResume()之間發生的事件:
1 ActivityController controller = 2 Robolectric.buildActivity(WelcomeActivity.class).create().start(); 3 Activity activity = controller.get(); 4 // assert that something hasn't happened 5 activityController.resume();
(2)完整的生命週期:
1 Activity activity = 2 Robolectric.buildActivity(WelcomeActivity.class).create().start().resume().visible().get();
(3)使用intent 來啓動activity:
1 Intent intent = new Intent(Intent.ACTION_VIEW); 2 Activity activity = 3 Robolectric.buildActivity(WelcomeActivity.class).withIntent(intent).create().get();
(4)保存狀態:
1 Bundle savedInstanceState = new Bundle(); 2 savedInstanceState.putExtra("user_age", "18"); 3 savedInstanceState.putExtra("user_name", "jay"); 4 Activity activity = Robolectric.buildActivity(WelcomeActivity.class).create() 5 .restoreInstanceState(savedInstanceState).get();