稱為架構有點言過其實,主要方便使用sublime開發java時做單元測試。 TestCase.java
import java.util.*;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public abstract class TestCase { /* 判斷實際結果與期望是否相等,並返回判定結果與運行位置資訊 @ actual 實際結果 @ expect 期望結果 傳回值:檢查結果的字串 備忘:同時緩衝檢查結果 */ public String assertEqual(Object actual, Object expect) { Throwable ex = new Throwable(); StackTraceElement[] stackElements = ex.getStackTrace(); TestResult r = new TestResult( actual.equals(expect), stackElements[1].getFileName(), stackElements[1].getLineNumber()); this.results.add(r); String s = String.format("%s, line %d, %s", r.fileName, r.line, actual.equals(expect) ? "SUCCESS" : "FAILED"); System.out.println(s); return s; } public ArrayList < TestResult > results = new ArrayList < TestResult > (); /* unitTest 執行用例的所有測試方法並輸出統計結果 傳回值: 統計結果字串 */ public String unitTest() { results = new ArrayList < TestResult > (); // 遍曆case對象所有開頭為test的public方法 Class < ? > cls = this.getClass(); Method[] methods = cls.getDeclaredMethods(); for (Method m: methods) { if (m.getName().startsWith("test")) { // 動態調用test方法 try { m.invoke(this); } catch (Exception e) {} } } // 統計失敗的檢查項 int failed = 0; for (TestResult tr: this.results) { if (!tr.Result) { failed += 1; } } String s = String.format("Tests: %d, Failed: %d", this.results.size(), failed); System.out.println(s); return s; } public static void main(String[] args) { TestCaseEx c = new TestCaseEx(); String s = c.assertEqual(1, 1); TestResult r = new TestResult(true, "TestCase.java", 61); ArrayList < TestResult > rs = new ArrayList < TestResult > (); rs.add(r); assert s.equals("TestCase.java, line 61, SUCCESS"); assert c.results.equals(rs); Class < ? > cls = c.getClass(); assert cls.getName().equals("TestCaseEx"); //測試取得類方法 Method[] methods = cls.getDeclaredMethods(); for (Method m: methods) { if (m.getName().equals("foo")) { try { assert(int) m.invoke(c) == 100; } catch (Exception e) {} } } s = c.unitTest(); rs = new ArrayList < TestResult > (); r = new TestResult(true, "TestCase.java", 98); rs.add(r); r = new TestResult(false, "TestCase.java", 102); rs.add(r); assert s.equals("Tests: 2, Failed: 1"); assert c.results.equals(rs); }}class TestCaseEx extends TestCase { public void testFoo() { this.assertEqual(1, 1); } public void testFoo2() { this.assertEqual(1, 0); } public int foo() { return 100; }}TestResult.java
public class TestResult { public TestResult(boolean ret, String fileName, int line) { this.Result = ret; this.fileName = fileName; this.line = line; } public boolean Result; // 測試結果 public String fileName; // 測試類別名 public int line; // assertEqual語句所在測試函數的調用位置 public static void main(String[] args) { TestResult tr = new TestResult(true, "tt", 100); assert tr.Result; assert tr.fileName == "tt"; assert tr.line == 100; TestResult tr2 = new TestResult(true, "tt", 100); assert tr.equals(tr2); } public boolean equals(Object o) { if (!(o instanceof TestResult)) { return false; } TestResult tr = (TestResult) o; return this.Result == tr.Result && this.fileName == tr.fileName && this.line == tr.line; }}使用代碼
public class demo { public static void main(String[] args) { TestString t = new TestString(); t.unitTest(); }}class TestString extends TestCase { public void testStringFunc() { String s = "abc"; this.assertEqual(s.startsWith("a"), true); this.assertEqual(s.indexOf("b"), 1); }}
輸出結果:
demo.java, line 11, SUCCESSdemo.java, line 12, SUCCESSTests: 2, Failed: 0[Finished in 1.8s]