# Testing
###### tags: `eGroupAI 開發規範`
> 測試用意不是來證明你是對的,而是你沒有錯。
---
> 參考資料
- [開源框架:JUnit Gossip - OpenHome.cc](http://openhome.cc/Gossip/JUnit/index.html)
- [JUnit介紹,JUnit是什麼?](http://tw.gitbook.net/junit/what-is-junit.html#)
## JUnit單元測試
> 簡介
- JUnit是個單元測試(Unit test)框架
- 單元測試指的是測試一個工作單元(a unit of work)的行為e.g. 建築橋墩:一個螺絲釘、一根鋼筋、一條鋼索、一公斤的水泥,都可謂是一個工作單元。
- 單元之間獨立
> Basic Annotations 常用註解
- @Test:表示要執行此區段裡的測試碼
- @Test(expected = Exception.class): 預期會拋出Exception.class的異常(e.g. 算術異常ArithmeticException)
- @Test(timeout = 100):測試方法預期執行不超過100**毫秒**
- @Before:每次測試前執行
- @After: 每次測試後執行
- @BeforeClass:在開始第一個測試前執行,只執行一次,必須為static void
- @AfterClass :全部測試完畢後執行,只執行一次,必須為static void
- @Ignore("忽略原因可以寫在這"):忽略測試,測試方法不會被執行
- @Runwith:運行器(Runner)執行之類別,可進行更改
- @Parameters:測試用參數宣告
> 上述範例
```java
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class BeforeAndAfterTest {
@BeforeClass
public static void beforeClass() {
System.out.println("BeforeClass");
}
@AfterClass
public static void afterClass() {
System.out.println("AfterClass");
}
@Before
public void before() {
System.out.println("Before");
}
@After
public void after() {
System.out.println("After");
}
@Test
public void test01() {
System.out.println("Test01");
}
@Test
public void test02() {
System.out.println("Test02");
}
}
```
執行結果:
```java
BeforeClass
Before
Test01
After
Before
Test02
After
AfterClass
```
**注意:1.所有測試方法必須使用public2.@BeforeClass與@AfterClass必須使用static void**
## 基本驗證
> JUnit 提供的 Assert 驗證方法
### **assertEquals**
- 值可能是類型有 int, short, long, byte, char or java.lang.Object
- 查看物件中存的值是否是期待的值,預期值(expected)=實際值(actual)
```
void assertEquals([String message], expected value, actual value)
//範例
assertEquals(expected, new Caculate().add(input1, input2));
```
### **assertTrue、assertFalse**
- boolan值
- 查看變數是是否為false或true
```
void assertTrue([String message], boolean condition)
void assertFalse([String message],boolean condition)
//範例
assertTrue(expected, new Member().isLogin(input));
assertFalse(expected, new Member().isLogin(input));
```
### **assertNull、assertNotNull**
- 用來查看物件是否為空和不為空
```
void assertNull([String message], java.lang.Object object)
void assertNotNull([String message], java.lang.Object object)
//範例
@Test
public void sample_assert_null(){
//arrange
Object expectNull = null;
Object expectNotNull = new Object();
//assert
Assert.assertNull(expectNull);
Assert.assertNotNull(expectNotNull);
}
```
### **assertSame、assertNotSame**
- 用來比較兩個物件的引用是否相等和不相等
```
void assertSame([String message], java.lang.Object expected, java.lang.Object actual)
void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual)
/*範例
*same 跟 equals 的差別其實就是平常使用 a == b 跟 a.equals(b) 是一樣的,看下面例子就可以了解
*/
@Test
public void sample_assert_same(){
//arrange
Object expect = new Object();
Object expectNotSame = new Object();
Object actual = expect;
//assert
Assert.assertSame(expect, actual);
Assert.assertNotSame(expectNotSame, actual);
}
```
### **assertArrayEquals**
- 用來比較預期數組和結果數組相等
```
void assertArrayEquals([String message], expectedArray, resultArray)
//範例
@Test
public void sample_assert_array(){
int[] expect = new int[]{1, 2, 3};
int[] actual = new int[]{1, 2, 3};
Assert.assertArrayEquals(expect, actual);
}
```
### **驗證集合**
```
//範例
@Test
public void sample_assert_collection(){
List<Integer> expect = Arrays.asList(1, 2, 3);
List<Integer> actual = Arrays.asList(1, 2, 3);
Assert.assertEquals(expect, actual);
}
```
## 撰寫第一個測試
> 起手式
先把JUnit框架引入
- 專案右鍵->Build Path->Libraries->AddLibrary
- 選擇JUnit4
- 在src/test/java 路徑下新增測試程式
- 右鍵新增Junit 測試檔案
- 在測試檔案上,右鍵->Run As->Junit Test,即可進行Junit 測試。
> 測試檔案命名方式
模組名稱或要被測試類別的名稱+Test
```java
//e.g. 如果模組為:Caculate,模組測試則是CaculateTest
//模組
public class Caculate {
public int add(int a,int b){
return a+b;
}
public int subtract(int a,int b){
return a-b;
}
public int multiply(int a,int b){
return a*b;
}
public int divide(int a,int b){
return a/b;
}
}
//模組測試
public class CaculateTest {
@Test
public void testAdd() {
assertEquals(3, new Caculate().add(2, 1));
}
@Test
public void testSubtract() {
assertEquals(8, new Caculate().subtract(9, 1));
}
@Test
public void testMultiply() {
assertEquals(6, new Caculate().multiply(3, 2));
}
@Test
public void testDivide() {
assertEquals(3, new Caculate().divide(9, 3));
}
@Ignore("可以在這說明忽略原因")
@Test(timeout=2000)
public void testWhile(){
while (true) {
System.out.println("run forever");
}
}
@Test(timeout=2000)
public void readFile(){
try {
Thread.sleep(2000);
} catch (Exception e) {
// TODO: handle exception
}
}
}
```
由上述模組測試範例,可以看到其中一個測試方法,以testAdd()為例
```java
//assertEquals(預期值, 測試值(可以method回傳));
@Test
public void testAdd() {
assertEquals(3, new Caculate().add(2, 1));
}
```
當預期值=測試值,代表其測試通過,反之,不通過。
> 參數化測試
- 使用多組數值進行測試
```java
/*
*1.更改默認的測試運行器Runner,@RunWith(Parameterized.class)
*2.宣告變量來存放預設值跟結果值
*3.宣告一個返回值為Collection的公共靜態方法,並使用@Parameters進行修飾
*/
@RunWith(Parameterized.class)
public class ParameterTest {
int expected=0;
int input1=0;
int input2=0;
@Parameters
public static Collection<Object[]> t(){
return Arrays.asList(new Object[][]{
{3,2,1},
{5,2,3},
{6,2,4}
});
}
public ParameterTest(int expected,int input1,int input2){
this.expected=expected;
this.input1=input1;
this.input2=input2;
}
@Test
public void testAdd(){
assertEquals(expected, new Caculate().add(input1, input2));
}
```
> 測試套件 Suite
- 批量運行,把所有測試方法集何在一個測試套件中,只須執行該套件一次即可。
```java
/*
*1.同時去執行SuiteClasses中的所有測試類
*2.寫一個作為測試套件的入口類,這個類別裡面不包含其他方法
*3.更改默認的測試運行器Runner,@RunWith(Suite.class)
*4.將要測試之類別,傳到Suite.SuiteClasses({})
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
TaskTest1.class,
TaskTest2.class,
ParameterTest.class,
Amount2RMBTest.class,
CaseIDGeneratorTest.class
})
public class SuiteTest {
}
```
- 也能直接產生Suite測試套件 右鍵->新增 JUnit Test Suite->選擇勾選測試類

> 測試慣例
- 軟體運作良好的事物都是經過測試檢驗的。
- 測試一點點,程式碼寫一點點,測試一點點,程式碼寫一點點......
- 確認所有測試都能100%通過。
- 要測試的程式碼是最可能錯誤的區域。
- 撰寫程式碼之前先寫單元測試
- 程式功能模組化
## 壓力測試
### **Jmeter**
下載
[http://jmeter.apache.org/download_jmeter.cgi](http://jmeter.apache.org/download_jmeter.cgi)
教學
[http://cloudchen.logdown.com/posts/247932/apache-jmeter-tool-for-load-test-and-measure-performance](http://cloudchen.logdown.com/posts/247932/apache-jmeter-tool-for-load-test-and-measure-performance)