今天要學的是新篇章,測試功能
Tim老師教的是 Junit4,所以我練習也是用這版本
BankAccount.java
package bankAcoount;public class BankAccount {
private String firstName;
private String lastName;
private double balance; public BankAccount(String firstName, String lastName, double balance) {
this.firstName = firstName;
this.lastName = lastName;
this.balance = balance;
}
// The branch argument is true if the customer is performing the transaction
// at a branch, with a teller, otherwise is at an ATM
public double deposit(double amount, boolean branch) {
balance += amount;
return balance;
} // The branch argument is true if the customer is performing the transaction
// at a branch, with a teller, otherwise is at an ATM
public double withdraw(double amount, boolean branch) {
balance -= amount;
return balance;
} public double getBalance() {
return balance;
} // More methods that use firstName, lastName, and perform other functions
}
接著對著 class name 點右下 More actions
點第一個 Create Test
本課學的是 Junit 4,還要記得把下面的 Member 都打勾
BankAccountTest.java
package bankAcoount;import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { @Test
public void deposit() {
} @Test
public void withdraw() {
} @Test
public void getBalance() {
}}
系統會新增一個 class,一開始都是空的
修改 BankAccountTest.java
package bankAcoount;import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { @Test
public void deposit() {
fail("Not yet implement");
} @Test
public void withdraw() {
} @Test
public void getBalance() {
} @Test
public void dummyTest() {
assertEquals(20, 50);
}
}
接著右鍵點 Run
輸出結果:
第一個測試直接寫 fail 所以不會通過
最後一個測試寫,希望得到 20,但拿到的是 50,所以也沒通過
中間兩個測試都是空的,直接算通過
所以就是 2 個通過、2 個失敗
修改 BankAccountTest.java
@Test
public void deposit() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00);
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
assertEquals(1200.00, account.getBalance(), 0);}
測試結果:
通過
assertEquals()
的參數分別為,希望得到的結果、實際給的數字,相差多少
不想一次運行所有測試可以只點行號旁邊的圖案,就可以單獨運行那個測試
修改 BankAccountTest.java
package bankAcoount;import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { @Test
public void deposit() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00);
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
} @Test
public void withdraw() {
fail("Not yet implement");
} @Test
public void getBalance() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00);
account.deposit(200.00, true);
assertEquals(1200.00, account.getBalance(), 0);
}}
測試結果:
通過,除了
withdraw()
主要是測試 getBalance()
Tim老師提醒說,所有的測試案例應該要可以分別單獨運行
所以 deposit()
也一起修改了
修改 BankAccountTest.java
package bankAcoount;import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { @Test
public void deposit() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00);
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
} @Test
public void withdraw() {
fail("Not yet implement");
} @Test
public void getBalance_deposit() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00);
account.deposit(200.00, true);
assertEquals(1200.00, account.getBalance(), 0);
} @Test
public void getBalance_withdraw() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00);
account.withdraw(200.00, true);
assertEquals(800.00, account.getBalance(), 0);
}}
測試結果:
通過,除了
withdraw()
Tim老師又提醒說,測試名要有相關,就改成能直接看懂的名稱了
一個存款,一個提款,都符合希望得到的結果(1000 + 200=1200,1000–200=800)
BankAccount.java
package bankAcoount;public class BankAccount {
private String firstName;
private String lastName;
private double balance; public static final int CHECKING = 1;
public static final int SAVING = 1; private int typeOfAccount; public BankAccount(String firstName, String lastName, double balance, int typeOfAccount) {
this.firstName = firstName;
this.lastName = lastName;
this.balance = balance;
this.typeOfAccount = typeOfAccount;
}
// The branch argument is true if the customer is performing the transaction
// at a branch, with a teller, otherwise is at an ATM
public double deposit(double amount, boolean branch) {
balance += amount;
return balance;
} // The branch argument is true if the customer is performing the transaction
// at a branch, with a teller, otherwise is at an ATM
public double withdraw(double amount, boolean branch) {
balance -= amount;
return balance;
} public double getBalance() {
return balance;
} public boolean isChecking() {
return typeOfAccount == CHECKING;
} // More methods that use firstName, lastName, and perform other functions
}
修改 BankAccountTest.java
package bankAcoount;import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { @Test
public void deposit() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
} @Test
public void withdraw() {
fail("Not yet implement");
} @Test
public void getBalance_deposit() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
account.deposit(200.00, true);
assertEquals(1200.00, account.getBalance(), 0);
} @Test
public void getBalance_withdraw() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
account.withdraw(200.00, true);
assertEquals(800.00, account.getBalance(), 0);
} @Test
public void isChecking_true() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
assertTrue(account.isChecking());
}}
測試結果:
通過,除了
withdraw()
新增一個測試,帳戶類型是否為支票戶
修改 BankAccountTest.java
@Test
public void isChecking_true() {
BankAccount account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.SAVING);
assertTrue("The account is NOT a checking account", account.isChecking());
}
測試結果:
java.lang.AssertionError: The account is NOT a checking account
at org.junit.Assert.fail(Assert.java:89)
at org.junit.Assert.assertTrue(Assert.java:42)
at bankAcoount.BankAccountTest.isChecking_true(BankAccountTest.java:38)
(以下省略)
改成存戶,測試就沒通過,還可自訂錯誤提示
修改 BankAccountTest.java
package bankAcoount;import org.junit.Before;
import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { private BankAccount account; @Before
public void setup() {
account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
System.out.println("Running a test...");
} @Test
public void deposit() {
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
} @Test
public void withdraw() {
fail("Not yet implement");
} @Test
public void getBalance_deposit() {
account.deposit(200.00, true);
assertEquals(1200.00, account.getBalance(), 0);
} @Test
public void getBalance_withdraw() {
account.withdraw(200.00, true);
assertEquals(800.00, account.getBalance(), 0);
} @Test
public void isChecking_true() {
assertTrue("The account is NOT a checking account", account.isChecking());
}}
測試結果:
Running a test…
java.lang.AssertionError: Not yet implement
at org.junit.Assert.fail(Assert.java:89)
at bankAcoount.BankAccountTest.withdraw(BankAccountTest.java:26)
(省略部份)
Running a test…
Running a test…
Running a test…
Running a test…
把之前測試都會使用的部份,抽出來放到 setup()
裡面
跑每個測試的時候,都會運行一次
修改 BankAccountTest.java
package bankAcoount;import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;import static org.junit.Assert.*;public class BankAccountTest { private BankAccount account; @BeforeClass
public static void beforeClass(){
System.out.println("This executes before any test cases");
} @Before
public void setup() {
account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
System.out.println("Running a test...");
} @Test
public void deposit() {
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
} @Test
public void withdraw() {
fail("Not yet implement");
} @Test
public void getBalance_deposit() {
account.deposit(200.00, true);
assertEquals(1200.00, account.getBalance(), 0);
} @Test
public void getBalance_withdraw() {
account.withdraw(200.00, true);
assertEquals(800.00, account.getBalance(), 0);
} @Test
public void isChecking_true() {
assertTrue("The account is NOT a checking account", account.isChecking());
} @AfterClass
public static void afterClass(){
System.out.println("This executes after any test cases.");
}}
測試結果:
This executes before any test cases
Running a test…
java.lang.AssertionError: Not yet implement
at org.junit.Assert.fail(Assert.java:89)
at bankAcoount.BankAccountTest.withdraw(BankAccountTest.java:33)
(省略部份)
Running a test…
Running a test…
Running a test…
Running a test…
若不想每一次都執行,只想在測試案例之前或之後執行一次就好,則可以使用 @BeforeClass
跟 @AfterClass
Tim 老師提醒說,若是在測試結果中,This executes before any test cases 這句若跑到下面,並不代表執行順序就是那樣
修改 BankAccountTest.java
package bankAcoount;import org.junit.*;import static org.junit.Assert.*;public class BankAccountTest { private BankAccount account;
private static int count; @BeforeClass
public static void beforeClass(){
System.out.println("This executes before any test cases. Count = " + count++);
} @Before
public void setup() {
account = new BankAccount("Tim", "Jimmy", 1000.00, BankAccount.CHECKING);
System.out.println("Running a test...");
} @Test
public void deposit() {
double balance = account.deposit(200.00, true);
assertEquals(1200.00, balance, 0);
} @Test
public void withdraw() {
fail("Not yet implement");
} @Test
public void getBalance_deposit() {
account.deposit(200.00, true);
assertEquals(1200.00, account.getBalance(), 0);
} @Test
public void getBalance_withdraw() {
account.withdraw(200.00, true);
assertEquals(800.00, account.getBalance(), 0);
} @Test
public void isChecking_true() {
assertTrue("The account is NOT a checking account", account.isChecking());
} @After
public void teardown(){
System.out.println("Count = " + count++);
} @AfterClass
public static void afterClass(){
System.out.println("This executes after any test cases. Count = " + count++);
}}
測試結果:
This executes before any test cases. Count = 0
Running a test…
Count = 1
java.lang.AssertionError: Not yet implement
at org.junit.Assert.fail(Assert.java:89)
at bankAcoount.BankAccountTest.withdraw(BankAccountTest.java:31)
Running a test…
Count = 2
Running a test…
Count = 3
Running a test…
Count = 4
Running a test…
Count = 5
This executes after any test cases. Count = 6
新增了一個 @After
,每個測試案例都會執行一次
還加入了計數器,看著數字變化就能知道執行的順序為何
好處是就算測試結果的順序顯示亂掉了,也能從計數器看出順序
修改 BankAccount.java
// The branch argument is true if the customer is performing the transaction
// at a branch, with a teller, otherwise is at an ATM
public double withdraw(double amount, boolean branch) {
if ((amount > 500.00) && !branch) {
throw new IllegalArgumentException();
}
balance -= amount;
return balance;
}
修改 BankAccountTest.java
@Test
public void withdraw() {
double balance = account.withdraw(600.00, true);
assertEquals(400.00, balance, 0);
}
測試結果:
全通過
修改了 withdraw()
跟測試案例
若從 ATM 提款大於 500 元就會報錯
修改 BankAccountTest.java
@Test
public void withdraw_branch() {
double balance = account.withdraw(600.00, true);
assertEquals(400.00, balance, 0);
}@Test
public void withdraw_notBranch() {
double balance = account.withdraw(600.00, false);
assertEquals(400.00, balance, 0);
}
測試結果:
This executes before any test cases. Count = 0
Running a test…
Count = 1
java.lang.IllegalArgumentException
at bankAcoount.BankAccount.withdraw(BankAccount.java:32)
at bankAcoount.BankAccountTest.withdraw_notBranch(BankAccountTest.java:37)
Running a test…
Count = 2
Running a test…
Count = 3
Running a test…
Count = 4
Running a test…
Count = 5
Running a test…
Count = 6
This executes after any test cases. Count = 7
拆成兩隻測試
跟我們預期的一樣,第二次測試沒有通過
但我們這邊本來就是設計成能拋錯,代表有通過才是
不應該歸類在沒通過
修改 BankAccountTest.java
@Test(expected = IllegalArgumentException.class)
public void withdraw_notBranch() {
double balance = account.withdraw(600.00, false);
assertEquals(400.00, balance, 0);
}
測試結果:
全通過
修改的方法,在 @Test
旁邊加上參數即可
若照我們預期拋出來這個錯誤,那代表測試成功
@Test
public void withdraw_branch() {
account.withdraw(600.00, true);
}@Test(expected = IllegalArgumentException.class)
public void withdraw_notBranch() {
account.withdraw(600.00, false);
}
其實 asserEquals()
在這裡沒用到,直接移除也行
不會影響到運行結果
@Test //(expected = IllegalArgumentException.class)
public void withdraw_notBranch() {
try {
account.withdraw(600.00, false);
} catch (IllegalArgumentException ignored) {
}
}
注意 @Test
後面註釋掉了
這種寫法是 Junit4 之前的寫法
@Test //(expected = IllegalArgumentException.class)
public void withdraw_notBranch() {
try {
account.withdraw(600.00, true);
fail("Should have thrown and IllegalArgumentException");
} catch (IllegalArgumentException ignored) { }
}
測試結果:
This executes before any test cases. Count = 0
Running a test…
Count = 1
java.lang.AssertionError: Should have thrown and IllegalArgumentException
at org.junit.Assert.fail(Assert.java:89)
at bankAcoount.BankAccountTest.withdraw_notBranch(BankAccountTest.java:38)
This executes after any test cases. Count = 2
加上自訂錯誤提示,就這樣寫