JUnit Cookbook

类别:Java 点击:0 评论:0 推荐:

这里有一些例子奉献给你,利用JUnit来编写和组织你自己的测试。

简单的测试案例

你怎样编写测试代码?

    最简单的方法是在调试器中写一条代码了,然后修改调试器而不用重新编译。最后还得判断所看到的最终运行的是哪个对象。

    同时,你也可以把测试代码作为完整的语句打印到标准输出流,例如:
      public class Car{
        public int getWheels() {
          return 4;
        }
      }

      //执行测试的类
      public class testCar {
        public static void main(String[] args) {
          testCar myTest = new testCar();
          myTest.testGetWheels();
        }
        public testGetWheels () {
          int expectedWheels = 4;
          Car myCar = Car();
          if (expectedWheels==myCar.getWheels())
            System.out.println("test [Car]: getWheels works perfected!");
          else
            System.out.println("test [Car]: getWheels DOESNT work!");
       }
      }

    但是,两种测试风格都有局限性,因为他们需要程序员对结果进行判断与分析。同样,有时我只需要了解一条调试代码的结果,但有时在一个程序中却有太多的输出流,从而导致恐怖的"卷轴乱跳"。
   
    JUnit测试就不需要程序员来解释,并且也能在同一时间方便地执行许多的测试。当你需要测试时,请按照以下方法:

  1.构造一个TestCase类的实例;
  2.创建一个构造器接收String参数来访问超类;
  3.覆盖runTest()方法;
  4.当你需要检测值时,调用带有boolean返回类型的方法assertTrue(),来判断是否测试成功。

    例如,要测试两个Money对象的总和是否和预测的值相同时,就这样写:

     public void testSimpleAdd() {
       Money m12CHF= new Money(12, "CHF");
       Money m14CHF= new Money(14, "CHF");
       Money expected= new Money(26, "CHF");
       Money result= m12CHF.add(m14CHF);
       assertTrue(expected.equals(result));
     }   

   如果你需要一个类似已存在的测试时,只需写一个Fixture来代替。当你需要一次运行很多测试时,创建一个Suite即可。
    
    Fixture

    如果你有两个以上对同一组对象基于相似或相同的测试时,该怎么办?

    测试将创建一组(待测)对象为条件(如:Money f12CHF,Money m14CHF)。这组对象就叫做测试Fixture。当你在写测试的时候经常会发现,花费许多时间写Fixture会比你进行实际测试更有价值。

    某种程度上,创建Fixture代码会比在构造器上小心翼翼更简单。另一方面,一个更大的优势来自于能够复用这些Fixture代码,你能经常地在各种测试代码中使用同样的Fixture。每个案例对信息和参数做细微地调整再送给Fixture,就可以测试不同地结果了。

    按照这样,你就可以有一个公有的fixture了:

  1.创建一个TestCase的子类;
  2.创建一个可接收String类型参数的构造器,再传递给超类;
  3.为每一Fixture部分增加一个实例变量;
  4.覆盖setUp()方法来初始化变量,初始化所有测试的Fixture,甚至可以在setUp中建立网络连接。
  5.tearDown()释放你在setUp()中分配的永久性资源,如数据库连接。

    例如,给12瑞士法郎、14瑞士法郎、28美元的不同组合写测试方案,首先就要创建一个Fixture:

      public class MoneyTest extends TestCase {
        private Money f12CHF;
        private Money f14CHF;
        private Money f28USD;
   
        protected void setUp() {
          f12CHF= new Money(12, "CHF");
          f14CHF= new Money(14, "CHF");
          f28USD= new Money(28, "USD");
       }
     }
   
    只需适当的编写Fixture,就可以随心所欲地进行测试了。
   
    Test Case
   
    在有了Fixture后怎样编写和调用单独的测试呢?

    test case来简单代替Fixture,创建TestCase类的匿名子类并覆盖runTest()方法。为单独的测试建立匿名子类。你会注意到有少数这样的测试会占用很多行代码来实现。

    JUnit提供更加简明的方法,你需要这样:

      1.在fixture类中在创建test case方法,需要声明为Public,否则将不能通过映射调用。
      2.创建一个TestCase类的实例,并传递test case方法的名字给构造器。

    例如,对Money和MoneyBag进行加法运算:

      public void testMoneyMoneyBag() {
      // [12 CHF] + [14 CHF] + [28 USD] == {[26 CHF][28 USD]}
        Money bag[]= { f26CHF, f28USD };
        MoneyBag expected= new MoneyBag(bag);
        assertEquals(expected, f12CHF.add(f28USD.add(f14CHF)));
     }

   创建MoneyTest的实例,并像这样运行test case:
     new MoneyTest("testMoneyMoneyBag")

   当测试运行时,各种测试方法将会被自动检测、运行。
  
   一旦需要进行几个测试时,需要把他们组织在Suite中。
  
    Suite

    怎样一次性执行多个测试呢?

    当你手头有多个测试时,第一反应就会想把他们放在一起测试,这样会更简单。在此之前,你会一个个地单独测试,直到感到厌倦。那么现在JUnit提供一个对象——TestSuite,它可以把许多测试放在一起。

    例如,进行单一测试,就像这样:
      TestResult result= (new MoneyTest("testMoneyMoneyBag")).run();
   
    进行两个案例的集成测试,就像这样:

      TestSuite suite= new TestSuite();
      suite.addTest(new MoneyTest("testMoneyEquals"));
      suite.addTest(new MoneyTest("testSimpleAdd"));
      TestResult result= suite.run();

    另一种方法就是让JUnit从TestCase中抽取suite。这样就可以把TestCase类传递给TestSuit构造器。
      TestSuite suite= new TestSuite(MoneyTest.class);
      TestResult result= suite.run();

    用手工方法把多个测试案例的子集包含进suite,suite会自动的选择最佳方案。它能避免新增测试案例引起的重复更新suite代码。

    TestSuite不仅包含TestCase,也包含满足Test接口的其他对象。例如,在你的代码中可以创建一个TestSuite,在我的代码中也可以,通过创建TestSuite,都可以把他们包含进来:

      TestSuite suite= new TestSuite();
      suite.addTest(Kent.suite());
      suite.addTest(Erich.suite());
      TestResult result= suite.run();
   
    TestRunner

    怎样既可以测试又可以收集它们的结果呢?

    之前你可以创建一个test suite,并执行。JUnit提供众多的工具来定义suite并执行并显示结果。可以把集成测试和TestRunner工具通过静态方法suite()很好的结合,并返回test suite。
     
      public static Test suite() {
        TestSuite suite= new TestSuite();
        suite.addTest(new MoneyTest("testMoneyEquals"));
        suite.addTest(new MoneyTest("testSimpleAdd"));
        return suite;
     }

    如果一个TestCase类不能定义suite()方法,TestRunner将会提取suite并填充以“test”开始的方法。
   
    JUnit也为TestRunner提供图像和文字两种界面,输入java junit.awtui.TestRunner或者junit.swingui.TestRunner,图形用户界面就会呈现:

    1.在输入框中选择适当的项目,
    2.点击Run按钮开始测试,
    3.下面的指示器有红绿两种,红代表失败,
    4.在列表中查看失败的测试。

    失败的情况下JUnit会在下面进行错误列表,JUnit会加以区别是failures还是errors。失败是指结果和断言(assertion)不一致,错误是指像ArrayIndexOutOfBoundsException这样的异常。如下图:
                   
   
    在动态编程环境中类似JAVA的VisualAge所支持”hot code update“,就可以始终使用JUnit的窗口。其他不支持这种特征的环境中进行不同测试时,也可以把JUnit的窗口关闭再打开,但这是很单调和浪费时间的。一种择中选择是用JUnit的AWT和Swing界面junit.runner.LoadingTestCollector。LoadingTestCollector会在不同测试时重新装载待测类。如果使用这个功能,”Reload classes every run“这个按钮将置为不可选。

    JUnit有一系列接口,在命令提示符下运行java junit.textui.TestRunner,在后面加上带有suite方法的类。那么将会以文字界面输出,择中办法是在TestCase类中调用定义好的main方法。

    例如,在TestRunner中运行MoneyTest:
      public static void main(String args[]) {
       junit.textui.TestRunner.run(suite());
      }

   通过定义main方法,只需在命令提示符中输入java MoneyTest即可。
   当然,不管使用图形界面或文字界面,都必须确认junit.jar文件在你的CLASSPATH中。

本文地址:http://com.8s8s.com/it/it16625.htm