JMUnit 1.0
-Java Micro Unit-¬
May, 2006
JMUnit 1.0
1 – JMUnit
软件测试是计算机编程的强有力的技术手段,程序员首先编写一个测试用例,然后编写允许测试过程的代码,这方面在互联网上有很多的参考资料以及一些参考书。这种方法的最大好处就是能尽快的发现代码中潜在的错误,并且能够完成一组测试的自动化,从而提高程序的性能。然而,程序员编写测试用例需要使用测试框架。
xUnit是编写测试用例最常用的框架。实际上,它是在Kent Beck的设计基础之上的适用于不同目的以及不同编程语言一组测试框架。JUnit是一个非常好的基于xUnit的Java测试框架,但是不能工作在Java Micro Edition (Java ME or J2ME)环境,因为Java Micro Edition没有JUnit使用的Java的Reflection API。JMUnit (Java Micro Unit) 的主要目的就是允许移动程序开发者们使用一个有效的、易用的、简单的测试框架来测试他们的Java代码。
2 – Assertions
当前的版本包括所有的JUnit具备的基本的断言,并且还进行了一些扩充,尽管这些扩充还没有实现,但是JMUnit 希望未来版本可以创建一些高级断言。框架有两个发行的版本, 一个用于CLDC 1.0,另一个用于CLDC 1.1,他们之间唯一的不同是CLDC 1.1的发行版本包括适用于浮点的assertionEquals() 方法,当然还需要不断改进。所有断言包括: assertTrue(), assertFalse(), assertSame(), assertNotSame(), assertEquals(), assertNotEquals(), assertNull() and assertNotNull()。当然还有 fail(), setUp() and tearDown()方法。
3 – Test Case
测试用例类继承自jmunit.framework.cldc1X.TestCase (关于cldc1X, 必须将 "X"写为0或1). 所有的测试方法必须在测试用例类中。 你可以参考如下的示例:
package test.com.foo;
import jmunit.framework.cldc10.TestCase;
import jmunit.framework.cldc10.AssertionFailedException;
import com.foo.Foo;
public class FooTest extends TestCase{
}
尽管类名没有必要像JUnit那样以前缀"Test"开始, 但是这样做是一个好习惯,因为这可以帮助你确定这是一个测试用例。对于方法名最好也以前缀"test"开始,尽管这不是必须的。 TestCase类有一个abstract方法和一个有两个参数的构建函数,因此它的子类必须像下面的示例:
public class FooTest extends TestCase
{
public FooTest()
{
super(0, "FooTest");
}
public void test(int testNumber) throws Throwable
{
switch(testNumber)
{
}}}
TestCase的构建函数需要一个整型值和一个字符串,整型值表示这个类包含多少个测试,当你在类中增加一个新测试方法后你必须增加这个整数值,否则他不会执行。字符串属于识别字符串,如果你使用了TestSuite,则字符串是不必要的。通常字符串是类名,但也可以是任意信息,字符串会显示在JMUnit界面。
方法test(int testNumber)被框架使用来执行你的测试,因为Java ME没有Reflection API,不能像JUnit那样在运行时找到测试方法并执行。因此,你每增加一个新的测试方法,就应该增加构建函数的整形值参数并在switch结构中增加一项。令人遗憾的是,你必须手工填写switch结构。这个方法可以抛出一些事件(比如它执行失败了), 因此这个测试方法有throws Throwable声明。 注意,如果有3个测试方法, super construtor中的整数值必须为3,并且switch结构必须覆盖0~2,并且从case 0开始。如果你没有这样做JMUnit将可能会产生不能预料的行为。看下面的示例:
public class FooTest extends TestCase
{ public FooTest(){
super(3, "FooTest");}
public void test(int testNumber) throws Throwable
{ switch(testNumber){
case 0: testIsEmpty();break;
case 1: testAdd(3, 5, 8);break;
case 2: testAdd(2, 1, 3);break;
default: break;}}
public void testIsEmpty() throws AssertionFailedException
{
Foo foo = new Foo();
assertTrue(foo.isEmpty());
foo.add(new Object());
assertFalse(foo.isEmpty());
}
public void testAdd(int addend, int augend, int expected)
{ Foo foo = new Foo();int actual = foo.add(addend, augend);assertEquals("testAdd", expected, actual);
}}
注意上面的例子尽管只有2个测试方法,但是其中的一个使用了2次,因此构造函数中的整数值应该是3,而不是2 。JMUnit和JUni有一点很大的不同,那就是JMUnit允许测试方法带有参数,这在某些测试技术中非常有用。在switch结构的case语句中可以书写很多代码,但是这不是良好的习惯。你应该将代码书写到测试方法中,如果测试方法使用断言方法,则必须有 throws AssertionFailedException语句,这个异常被框架使用进行验证,然而testAdd(int addend, int augend, int expected)没有,因此这个示例不会通过编译。
4 – Test Suite
Java ME程序和Java版的程序相比非常小,并且相当一部分代码是很难进行测试的(比如多线程和GUI),因此能够进行测试的部分通常非常小,但是也需要少量的测试用例。如果开发者需要进行更多的测试,则应该使用Test Suite。如果测试例程不适合整合成一个,那么使用Test Suite来管理它们是一个很好的选择。JMUnit适合在比移动电话更复杂的目标设备的程序中使用,比如PDA,拥有大量的代码,有可能创建很多测试用例,在将来发行时,将它们放在不同的测试套件中,并将所有的测试套件放到一个根测试套件中。
为了创建一个测试套件, 首先你需要一个或多个测试用例, 否则测试套件是毫无意义的。你必须创建一个jmunit.framework.cldc1X.TestSuite (关于cldc1X, 必须将 "X"写为0或1)的子类。这个abstract class 有带有一个String类型参数的构造函数,String类型参数标识这个测试套件。如果在整个程序中只有一个测试套件的话,则此String类型参数是没有用的,String类型参数的值可以是"Test Suite" 或其它。但是如果有很多测试套件,它可以帮助用来看到底是哪个在运行。 尽量使用一些有意义的名字,如 "Test of the Data Sctructure" 或 "A.I. Test"。请看如下示例:
package test.com.foo;
import jmunit.framework.cldc10.TestSuite;
public class Suite extends TestSuite
{
public Suite()
{
super("All Tests");}}
作为唯一的函数,可以在其中加一些测试用例并执行所有已添加的例程,测试套件使用起来很简单。你仅仅需要在构造函数内使用add(TestCase testCase)方法,参数是一个测试用例类的对象,你可以使用此方法加入你所需要的测试用例。
public class Suite extends TestSuite
{
public Suite()
{
super("All Tests");
add(new FooTest());
add(new RMSTest());
add(new MIDletTest());
}}
5 – Testing
现在你已经知道了可以使用的断言,如何创建一个测试方法和测试用例,并且最终如何在测试套件中管理它们,现在可以执行它们了。这个发行版本是使用Eclipse 和 Sun Wireless Toolkit创建和测试的,因此不保证JMUnit工作在不同的环境下;为了工作在其它环境,也许需要在设置上进行一些改动(不是修改JMUnit代码)。在项目中加入框架并创建测试类后,你就可以执行了。TestCase和TestSuite都是Test类的抽象子类,Test类是MIDlet的子类,因此开发者可以在模拟器中执行。
框架使用模拟器的界面显示结果,作为一个MIDlet运行其中的一个测试用例(或整个测试套件)将显示一个带有两个命令的屏幕: Exit 和 Test,Exit命令可以关闭(退出)JMUnit,Test命令则开始测试方法的执行。屏幕带有一个好像Eclipse中JUnit的插件的条带,它在方法执行是增长、变绿,但是如果有任何测试抛出事件或失败,则条带变红。
当然还有一些信息显示在屏幕上,测试的数量,通过的数量,失败的数量,抛出异常的数量,所有这些在方法执行时更新。 框架还管理一个计数器,能显示测试所用的时间,并且能够显示在屏幕上。当前的JMUnit版本还没有合适的GUI来显示失败的测试,它使用printStackTrace()方法来显示控制台信息,像代码行, 断言失败,测试方法和测试用例。框架还在控制台给每个失败加了一个标题。在屏幕中,唯一有用的信息则是已经发生的失败的数量,这个信息也用在错误测试 (throwed something)。
---------------
译者注:这是一篇去年就完成的手册,翻译完后一直就放着,今天才想起来,于是就挂到了这里;其中也可能有不太准确的地方,但是应该不影响对内容的理解。
Denlee