在当前java环境中,多数都会集成了Junit测试框架,小伙伴们知道它该怎么使用吗?它的原理又是什么呢?下面就听小编来慢慢讲解讲解吧。
Junit单元测试原理及使用
我们使用一个东西, 一定要做到知其然和知其所以然,现在,我们就通过一个简单的例子来了解一下Junit的使用及原理。
示例:
/** * A sample test case, testing <code>java.util.Vector</code>. * */ public class VectorTest extends TestCase { protected Vector fEmpty; protected Vector fFull; public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } protected void setUp() { fEmpty = new Vector(); fFull = new Vector(); fFull.addElement(new Integer(1)); fFull.addElement(new Integer(2)); fFull.addElement(new Integer(3)); } public static Test suite() { return new TestSuite(VectorTest.class); } public void testCapacity() { int size = fFull.size(); for (int i = 0; i < 100; i++) fFull.addElement(new Integer(i)); assertTrue(fFull.size() == 100 + size); } public void testClone() { Vector clone = (Vector) fFull.clone(); assertTrue(clone.size() == fFull.size()); assertTrue(clone.contains(new Integer(1))); } public void testContains() { assertTrue(fFull.contains(new Integer(1))); assertTrue(!fEmpty.contains(new Integer(1))); } public void testElementAt() { Integer i = (Integer) fFull.elementAt(0); assertTrue(i.intValue() == 1); try { fFull.elementAt(fFull.size()); } catch (ArrayIndexOutOfBoundsException e) { return; } fail("Should raise an ArrayIndexOutOfBoundsException"); } public void testRemoveAll() { fFull.removeAllElements(); fEmpty.removeAllElements(); assertTrue(fFull.isEmpty()); assertTrue(fEmpty.isEmpty()); } public void testRemoveElement() { fFull.removeElement(new Integer(3)); assertTrue(!fFull.contains(new Integer(3))); } }
1)、主入口
public static void main(String[] args) { junit.textui.TestRunner.run(suite()); }
2)、suite()
public static Test suite() { return new TestSuite(VectorTest.class); }
这是JUnit使用TestSuite规定的模式,尤其是在命令行或图形界面下,只有定义了public static Test suite() 方法,框架才会按照我们的定义运行框架。
3)、new TestSuite(VectorTest.class)、
TestSuite是有三个构造函数的,一个没有参数,一个以Class为参数还有一个以Class和名字字符串作为参数。Class必须是实现了Test接口的子类,一般继承自TestCase,并且该类中定义了以Test开头没有参数的测试方法。
//构造函数 while (Test.class.isAssignableFrom(superClass)) { Method[] methods = superClass.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { addTestMethod(methods[i], names, theClass); } superClass = superClass.getSuperclass(); } //addTestMethod if (!isPublicTestMethod(m)) { if (isTestMethod(m)) addTest(warning("Test method isn't public: " + m.getName())); return; } names.addElement(name); addTest(createTest(theClass, name)); //isTestMethod private boolean isTestMethod(Method m) { String name = m.getName(); Class[] parameters = m.getParameterTypes(); Class returnType = m.getReturnType(); return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); }
所以,我们必须保证我们要在实现Test接口的子类中定义符合以上要求的测试类,否则,框架将不会运行我们的测试方法。
同时我们也看到,当我们将Test类传入TestSuite后,TestSuite将所有的test构造为TestCase实例,每个实例都会有一个名字,和要测试的方法。
//createTest (addTest(createTest(theClass, name))时调用) static public Test createTest(Class theClass, String name) { Constructor constructor; try { constructor = getTestConstructor(theClass); } catch (NoSuchMethodException e) { return warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"); } Object test; try { if (constructor.getParameterTypes() .length == 0) { test = constructor.newInstance(new Object[0]); if (test instanceof TestCase) ((TestCase) test) .setName(name); } else { test = constructor.newInstance(new Object[] { name }); } } catch (InstantiationException e) { return (warning("Cannot instantiate test case: " + name + " (" + exceptionToString(e) + ")")); } return (Test) test; }
在createTest(Class theClass, String name)方法中theClass是实现了Test接口的类,一般情况下是TestCase的子类。这样name就是TestCase的名字,用于标志一个测试。
在TestCase的protected void runTest() throws Throwable 方法中:
runMethod = getClass() .getMethod(fName, null); //获取方法名 runMethod.invoke(this, new Class[0]); //运行测试方法。
4)、测试开始
Test.run( TestResult) 是实际上调用TestResult.run( Test)。 //TestResult.run(Test) protected void run(final TestCase test) { startTest(test); Protectable p = new Protectable() { public void protect() throws Throwable { test.runBare(); } }; runProtected(test, p); endTest(test); }
这个方法也是一个模版方法, 关键是runProtected方法:
public void runProtected(final Test test, Protectable p) { try { p.protect(); } catch (AssertionFailedError e) { addFailure(test, e); } catch (ThreadDeath e) { // don't catch ThreadDeath by accident throw e; } catch (Throwable e) { addError(test, e); } }
这个方法起到的作用就是当测试出现异常或错误时会在TestResult中记录,如果是ThreadDeath 就继续抛出异常,程序可能会终止,如果是其他错误和异常,程序将继续运行。这也就是protect的含义。因此,我们抛出Assert中的异常时,不会影响下面的测试继续运行。
然在这个方法中传入的Protectable p的protect方法实际是调用了test.runBare();我们看到,TestRunner调用了Test的run(TestResult)方法后,TestResult实际上是在一个保护的环境下调用TestCase的runBase方法。也就是说如果我们自己的测试类没有继承TestCase,也要定义一个runBase方法,执行基本的操作。基于这一点,我们的测试类应该继承自TestCase。
以上就是关于Junit框架原理及如何使用的所有内容了,你了解了吗?还想知道更多java常见问题及解决方法的话,就请持续奇Q工具网吧。
推荐阅读: