基本概念
維基百科的定義:單元測試(又稱為模塊測試, Unit Testing)是針對程序模塊(軟件設(shè)計的最小單位)來進行正確性檢驗的測試工作标捺。程序單元是應用的最小可測試部件茶敏。在過程化編程中,一個單元就是單個程序、函數(shù)诬烹、過程等此虑;對于面向?qū)ο缶幊蹋钚卧褪欠椒庹ɑ悾ǔ悾┣⒊橄箢悺⒒蛘吲缮悾ㄗ宇悾┲械姆椒ā?/p>
《軟件測試方法和技術(shù)》(朱少民 清華大學出版社 2005年7月第一版):
單元測試是對軟件基本組成單元的測試褥符。單元測試的對象是軟件設(shè)計的最小單位——模塊洞渤。很多參考書中將單元測試的概念誤導為一個具體函數(shù)或一個類的方法。一個最小的單元應該有明確的功能属瓣、性能定義载迄、接口定義而且可以清晰地與其他單元區(qū)分開來。一個菜單抡蛙、一個顯示界面或者能夠獨立完成的具體功能都可以是一個單元护昧。某種意義上單元的概念已經(jīng)擴展為組件(component)
名詞解釋
- JUnit: java單元測試最普及的框架
- testCompile: 用于
src/test
下的代碼測試,在JVM環(huán)境下 - androidTestCompile: 用于
src/androidTest
下的代碼測試粗截,在Android device(or an emulator)
小特點說明
- 在JUnit 4中可以不用在測試方法前加
test
前綴了(JUnit 3中還需要加)
AS依賴
應用模塊的 build.gradle 文件中指定測試庫依賴項(來自Google官方文檔):
dependencies {
// Required for local unit tests (JUnit 4 framework)
testCompile 'junit:junit:4.12'
// Required for instrumented tests
androidTestCompile 'com.android.support:support-annotations:24.0.0'
androidTestCompile 'com.android.support.test:runner:0.5'
}
Android項目中惋耙,你創(chuàng)建單元測試文件在module-name/src/test/java/
路徑下。這個路徑在創(chuàng)建項目的時候已經(jīng)創(chuàng)建了。
你也需要設(shè)置項目依賴绽榛,如上例所示 JUnit4框架湿酸,如果你的單元測試需要用到Android的依賴,則需要Mockito庫灭美,下文有關(guān)于Mock的介紹推溃。
創(chuàng)建AS單元測試
注解解釋
注解可以方便的設(shè)置你想要測試的功能
- @BeforeClass:針對類中所有測試,只執(zhí)行一次届腐,且必須為static void
- @Before:初始化方法铁坎,針對每個測試方法執(zhí)行一次
- @Test:測試方法,包括使用斷言判定待測試方法的輸出是否正確犁苏、是否拋出特定異常等
- @After:釋放資源硬萍,針對每個測試方法執(zhí)行一次
- @AfterClass:針對所有測試,只執(zhí)行一次围详,且必須為static void
- @Ignore:忽略的測試方法
- @RunWith(Suite.class) @Suite.SuiteClasses({ *.class}) 指定測試套件朴乖,一次運行多個測試類中的測試方法
斷言
除了使用assertEquals、assertTrue助赞,為了提高可讀性寒砖,還可以使用JUnit4.4引入的Hamcrest框架,assertThat嫉拐。詳細的斷言可以看API文檔哩都。
舉個例子
用網(wǎng)上最流行的例子,Calculator.java
public class Calculator{
public double sum(double a, double b){
return0;
}
public double substract(double a, double b){
return0;
}
public double divide(double a, double b){
return0;
}
public double multiply(double a, double b){
return0;
}
}
相應的單元測試類
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 {
//expected: 6, sum of 1 and 5
assertEquals(6, mCalculator.sum(1, 5));
}
@Test
public void testSubstract() throws Exception {
assertEquals(1, mCalculator.substract(5,4));
}
@Test
public void testDivide() throws Exception {
assertEquals(4d, mCalculator.divide(20d, 5d));
}
@Test public void testMultiply() throws Exception {
assertEquals(10d, mCalculator.multiply(2d, 5d));
}
}
Mock
有時在單元測試中需要用到Android相關(guān)的類婉徘,比如說Context漠嵌、Activity,但是在其他JUnit中不存在這些類盖呼,這時我們就要用到Mock和Mockito儒鹿,是一個模擬測試框架,可以獲取你需要的各種類几晤。
- 如何依賴
repositories { jcenter() }
dependencies {
testCompile "org.mockito:mockito-core:2.+"
}
Mockito例子
更多信息見官網(wǎng)API文檔
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import android.content.SharedPreferences;
@RunWith(MockitoJUnitRunner.class)
public class UnitTestSample {
private static final String FAKE_STRING = "HELLO WORLD";
@Mock
Context mMockContext;
@Test
public void readStringFromContext_LocalizedString() {
// Given a mocked Context injected into the object under test...
when(mMockContext.getString(R.string.hello_word))
.thenReturn(FAKE_STRING);
ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);
// ...when the string is returned from the object under test...
String result = myObjectUnderTest.getHelloWorldString();
// ...then the result should be the expected one.
assertThat(result, is(FAKE_STRING));
}
}