现在的位置: 首页 > 综合 > 正文

首个单元测试

2013年11月02日 ⁄ 综合 ⁄ 共 7680字 ⁄ 字号 评论关闭

         一个单元测试是程序员编写的一段代码,用于执行另一段代码并确定那段代码的行为是否与程序员期望的一致.为了检验代码的行为与你期望的一致,你需要一些assertion(断言),它是个简单的方法调用,用于判断某个语句是否为真.具体的实现如下所示.

        public void asserTrue(boolean condition){

                if(!condition){

                      abort();

                }

       }  

由于某种原因,当调用assertTrue()的时候条件不成立,那么程序将被终止,事实上你可以用断言来判断所有的事物.

         既然我们经常需要检测是否相等,如果能够有一个专门针对于数字的断言将会更为方便.例如为了检测二个整数是否相等,我们可以编写如下的断言.

        public void  assertEquals(int a, int b){

                assertTrue(a==b);

        }

        为了使得概念更加具体,让我们来编写一个"寻找最大数"的函数,并对它进行测试.

        public class Largest {
             /**
              * return the Largest element of the list
              *
              * @param list A list of integers
              * @return The Largest number in the given List
              */
             public static int largest(int[] list){
                       int index,max=Integer.MAX_VALUE;
                       for(index=0; index<list.length;index++){
                                if(list[index]>max){
                                         max=list[index];
                                }
                       }
                       return max;
              }
       }

      你想有多少个测试?

      显然对于一个List而言,元素的位置对该方法的结果并不会产生影响;于是你马上会想到如下的测试(在下面我们将把输入输出写成"输入--->你所期望的输出"这样的格式)。

      [7,8,9]----->9

      [8, 9,7]----->9

      [9,7,8 ]----->9

      如果List中存在二个相等的最大值,将会出现什莫情况。

      [7,8,9,9,7]--->9

     如果这些元素是int类型,而不是对象类型,你可能不能不在意那个9会作为结果返回,只要返回其中的一个就行了。

     如果List中只有一个元素,那末结果会是什莫?

     [1]----->1

     如果List包含负数,结果有回是怎样?

      [-9,-8,-7]------->-7

      *测试一个简单的方法。

       首个测试非常的简单,因为除了代码以外还有许多的因素需要被测试:凌乱的类名,程序库的位置,还要确定代码能否被编译。在你的首个测试里假设一切都成立。

       首先,让我们传递一个没有重复的简单数组给函数,并对这种情况进行测试,下面是详细的代码。

       import junit.framework.TestCase;

       public class TestLarget extends TestCase {
              public TestLarget(String name){
                      super(name);
              }
              public void testSimply(){
                      assertEquals(9,Largest.largest(new int[] {7,8,9}));
              }
              public void assrtEquals(int a, int b){
                     assertTrue(a==b);
             }
      }

      运行刚才的代码后,你可能看到类似于下面的错误信息(在eclipse上的运行结果):

      junit.framework.AssertionFailedError: expected:<9> but was:<2147483647>
     at junit.framework.Assert.fail(Assert.java:47)
     at junit.framework.Assert.failNotEquals(Assert.java:282)
     at junit.framework.Assert.assertEquals(Assert.java:64)
     at junit.framework.Assert.assertEquals(Assert.java:201)
     at junit.framework.Assert.assertEquals(Assert.java:207)
     at TestLarget.testSimply(TestLarget.java:8)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at junit.framework.TestCase.runTest(TestCase.java:154)
     at junit.framework.TestCase.runBare(TestCase.java:127)
     at junit.framework.TestResult$1.protect(TestResult.java:106)
     at junit.framework.TestResult.runProtected(TestResult.java:124)
     at junit.framework.TestResult.run(TestResult.java:109)
     at junit.framework.TestCase.run(TestCase.java:118)
     at junit.framework.TestSuite.runTest(TestSuite.java:208)
     at junit.framework.TestSuite.run(TestSuite.java:203)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

        whoops!为什莫和我们期望的不一致那?原来max=Integer.MAX_VALUE;这行代码出现了错误,应该是max=0,我们的想法是初始化max这样的一个值,任何的数字和其比较之后,可以立刻的取代它。修改以后重新的编译,并最终通过测试。

        如果最大数位于List的不同位置,那末将会产生什莫样的情况,显然bug经常出现在边界位置,上面的例子中边界是指list的首个、最后一个位置,下面的代码中,我们把三个断言写在一个测试中,但是我们每次只添加一个断言。

       public void testOrder(){
               assertEquals(9,Largest.largest(new int[] {9,8,7}));
               assertEquals(9,Largest.largest(new int[] {7,9,8}));
               assertEquals(9,Largest.largest(new int[] {7,8,9}));
       }

       junit.framework.AssertionFailedError: expected:<9> but was:<8>
       at junit.framework.Assert.fail(Assert.java:47)
       at junit.framework.Assert.failNotEquals(Assert.java:282)
       at junit.framework.Assert.assertEquals(Assert.java:64)
       at junit.framework.Assert.assertEquals(Assert.java:201)
       at junit.framework.Assert.assertEquals(Assert.java:207)
       at TestLarget.testOrder(TestLarget.java:15)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
       at java.lang.reflect.Method.invoke(Unknown Source)
       at junit.framework.TestCase.runTest(TestCase.java:154)
       at junit.framework.TestCase.runBare(TestCase.java:127)
       at junit.framework.TestResult$1.protect(TestResult.java:106)
       at junit.framework.TestResult.runProtected(TestResult.java:124)
       at junit.framework.TestResult.run(TestResult.java:109)
       at junit.framework.TestCase.run(TestCase.java:118)
       at junit.framework.TestSuite.runTest(TestSuite.java:208)
       at junit.framework.TestSuite.run(TestSuite.java:203)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

        当我们测试到最后一个断言的时候,我们发现函数的最大值为什莫会是8那?好像代码根本没有考虑List的最后一个元素,原来代码中for循环结束太早了,一个典型的off-by-one错误的一个例子。在我们的代码中:

        for(index=0; index<list.length-1;index++){

        实际应该是:

        for(index=0; index<=list.length-1;index++){

        for(index=0; index<list.length;index++){

        在继承了c的语言(包括java)中,第二中表述方式比较常用并且容易阅读。修改代码后从新测试运行。

         现在检测存在重复最大值的情况,编写并运行下面的代码。

         public void testDups(){
                    assertEquals(9,Largest.largest(new int[] {9,7,8,9}));
         }

         测试的结果和我们期望的一致。接下来我们需要测试仅仅存在一个元素的List.

          public void testOne(){
                    assertEquals(1,Largest.largest(new int[] {1}));
         }       

         Hey,他通过了!你正在朝着正确的方向前进,并确定我们的例子中的bug已经被除去了。我们再来调试全部为负值的List.

         public void testNegative(){
                    assertEquals(-7,Largest.largest(new int[] {-7,-8,-9}));
         }  

         junit.framework.AssertionFailedError: expected:<-7> but was:<0>
        at junit.framework.Assert.fail(Assert.java:47)
        at junit.framework.Assert.failNotEquals(Assert.java:282)
        at junit.framework.Assert.assertEquals(Assert.java:64)
        at junit.framework.Assert.assertEquals(Assert.java:201)
        at junit.framework.Assert.assertEquals(Assert.java:207)
        at TestLarget.testNegative(TestLarget.java:23)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at junit.framework.TestCase.runTest(TestCase.java:154)
        at junit.framework.TestCase.runBare(TestCase.java:127)
        at junit.framework.TestResult$1.protect(TestResult.java:106)
        at junit.framework.TestResult.runProtected(TestResult.java:124)
        at junit.framework.TestResult.run(TestResult.java:109)
        at junit.framework.TestCase.run(TestCase.java:118)
        at junit.framework.TestSuite.runTest(TestSuite.java:208)
        at junit.framework.TestSuite.run(TestSuite.java:203)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

         whoops!这个零是从哪里来得那?看来用0初始化max是个错误的做法,因为我们实际需要初始             max=Integer.MIN_VALUE;从而使它比任何的负数都小.

【上篇】
【下篇】

抱歉!评论已关闭.