<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2006年2月25日

    測試驅(qū)動開發(fā)案例之自動售貨機(jī)(第1集)

    測試驅(qū)動開發(fā)(TDD, Test Driven Development)是一種很有意思的軟件開發(fā)方式,本集以較小的步伐體驗(yàn)TDD。

    /**  A program simulation of an automat.
     *
     *  Director: Zuo Baoquan
     *  Contact me:
     *     Blog:   http://www.tkk7.com/BaoquanInside
     *     MSN: Baoquan.Zuo [at] hotmail.com
     *     Email:  Baoquan.Zuo [at] gmail.com
     *
     *  Copyright 2006 BEC Studio
     */
     
    引言:
    (該問題截取自《面向?qū)ο蟮脑O(shè)計(jì)與模式》(Written by Cay Horstmann) Exercise 2.18
     
    設(shè)計(jì)并實(shí)現(xiàn)一個模擬自動售貨機(jī)的程序。通過給機(jī)器投入正確的硬幣,便可以購買到相應(yīng)的商品。用戶從一個可用的商品列表中選擇商品、投入硬幣并得到商品。如果沒有足夠的錢幣或由于此商品已銷售完畢,則將硬幣退回。操作員可以重新備并將錢幣取走。
     
     
    場景#1
    地點(diǎn):同濟(jì)大學(xué)西南樓
    涉眾:我,空自動售貨機(jī)
     
    寢室樓里面剛搬來了一臺空的自動售貨機(jī),那我們來測試一下:
     
    public class TestEmptyAutomat extends TestCase
    {
      public void testIsEmpty()
      {
        Automat automat = new Automat(); 
        assertTrue("it should be empty.", automat.isEmpty());
      }
    }
     
    Eclipse提示"Automat cannot be resolved to a type",好,看我的:
    public class Automat
    {
      public Automat()  // constructor stub
      {
      }
    }
     
    再露一手:
    //class Automat
    public boolean isEmpty()
    {
      return true;
    }
     
    全部保存,運(yùn)行測試,呵呵,綠色進(jìn)度條!測試成功!
     
    好,既然我們還沒有投過硬幣,那么余額應(yīng)該是0了~
     
    // class TestEmptyAutomat
    public void testBalance()
    {
      Automat automat = new Automat();
      assertEquals("the balance should be 0.", 0, automat.balance); 
    }
     
    繼續(xù)使用我們的法寶:
    // class Automat
    public final int balance = 0;
     
    運(yùn)行測試,yeah!
     
    看了一遍測試程序,決定優(yōu)化一下:
    public class TestEmptyAutomat extends TestCase
    {
      protected void setUp() throws Exception
      {
        super.setUp();
        automat = new Automat();
      }
     
      public void testIsEmpty()
      {
        assertTrue("it should be empty.", automat.isEmpty());
      }
     
      public void testBalance()
      {
        assertEquals("the balance should be 0.", 0, automat.balance); 
      }
     
      private Automat automat;
    }
    再運(yùn)行一次測試,呵呵,又是綠色!
     
    場景#2
    地點(diǎn):同濟(jì)大學(xué)西南樓
    涉眾:我,自動售貨機(jī)(有一瓶百事可樂)
     
    好消息,樓長在自動售貨機(jī)里面放了一瓶Pepsi。
     
    public class TestAutomatWithOnePepsi extends TestCase
    {
      protected void setUp() throws Exception
      {
        super.setUp();
        automat = new Automat();
        pepsi = new Pepsi();  // 一瓶百事可樂
        automat.add(pepsi);  // 樓長阿姨放的~
      }
      
      public void testEmpty()
      {
        assertFalse("it should not be empty.", automat.isEmpty());
      }
     
      public Automat automat;
      public Pepsi pepsi;
    }

    接著創(chuàng)建Pepsi類
     
    public class Pepsi
    {
      public Pepsi() // constructor stub
      {
       
      }
    }
     
    再給Automat添加add方法:
    // class Automat
    public void add(Pepsi pepsi)
    {
     
    }
     
    好,現(xiàn)在有兩個TC(Test Case)了,為了運(yùn)行兩個測試案例,我們來創(chuàng)建一個Test Suite:
    public class AutomatTests
    {
      public static Test suite()
      {
        TestSuite suite = new TestSuite("Test for net.mybec.automat");
        //$JUnit-BEGIN$
        suite.addTestSuite(TestAutomatWithOnePepsi.class);
        suite.addTestSuite(TestEmptyAutomat.class);
        //$JUnit-END$
       
        return suite;
      }
    }
     
    編譯成功,運(yùn)行AutomatTests,紅色進(jìn)度條。TestEmptyAutomat綠色,TestAutomatWithOnePepsi紅色。呵呵,看來要讓add做點(diǎn)事情了。
     
    // class Automat
    public void add(Pepsi pepsi)
    {
      goods.add(pepsi);
    }
     
    // 添加一個裝Pepsi的數(shù)組列表
    private final ArrayList<Pepsi> goods = new ArrayList<Pepsi>();

     
    // 修改isEmpty方法
    public boolean isEmpty()
    {
      return goods.isEmpty();
    }

     
    再次運(yùn)行AutomatTests,呵呵,綠色!我們喜歡!
     
    好,我們再看看Automat的余額:
     
    // class TestAutomatWithOnePepsi
    public void testBalance()
    {
      assertEquals("the balance should be 0.", 0, automat.balance);
    }
     
    運(yùn)行一遍測試,Ok。
     
     
    我們還沒有投硬幣,當(dāng)然不能買百事可樂了:
     
    // class TestAutomatWithOnePepsi
    public void testCanBuyWithoutBalance()
    {
      assertFalse("we cannot buy pepsi without money.", automat.canBuy(pepsi));
    }
    // class Automat
    public boolean canBuy(Pepsi pepsi)
    {
      return false;
    }
     
    我們太喜歡運(yùn)行測試了,于是又忍不住運(yùn)行了所有的自動測試(呵呵,實(shí)際上我們只需要點(diǎn)擊一個運(yùn)行按鈕)。又是綠色~
     
    好,如果Pepsi的價(jià)格是2元,我們投1塊錢試試~
     
    // class Pepsi
    public static final int PRICE = 2;
     
    // class TestAutomatWithOnePepsi
    public void testCanBuyWithOneYuan()
    {
      automat.put(1);
      assertFalse("we cannot buy pepsi with one yuan.", automat.canBuy(pepsi));
    }
     
    // class Automat
    public void put(int yuan)
    {
     
    }
     
    運(yùn)行測試,綠色。顯然1塊錢買不到百事可樂。那就投2塊錢吧:
     
    // class TestAutomatWithOnePepsi
    public void testCanBuyWithTwoYuan()
    {
      automat.put(2);
      assertTrue("we can not buy pepsi with two yuan.", automat.canBuy(pepsi));
    }
     
    運(yùn)行測試,紅色進(jìn)度條,JUnit提示“we can not buy pepsi with two yuan.” 天啊,這不公平。
    想起來了,Automat.put什么也沒做。于是我們添了幾筆:
     
    // class Automat
    public void put(int yuan)
    {
      balance += yuan;
    }
     
    public boolean canBuy(Pepsi pepsi)
    {
      return balance >= Pepsi.PRICE;
    }
     
    public int balance = 0;  // 去掉了final
     
    迫不及待地點(diǎn)擊了運(yùn)行按鈕,yeah!終于能買到喜歡的Pepsi了(因?yàn)榭吹搅司G色進(jìn)度條~)。
     
    于是急忙買了一瓶Pepsi:
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithTwoYuan()
    {
      automat.put(2);
      automat.buy(pepsi);
      assertTrue("the automat should be empty.", automat.isEmpty());
    }
    // class Automat
    public void buy(Pepsi pepsi)
    {
     
    }
     
    Run Tests, Failed. So,
    // class Automat
    public void buy(Pepsi pepsi)
    {
      goods.remove(pepsi);
    }
    Run Tests again, OK.
     
     
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithTwoYuan()
    {
      automat.put(2);
      automat.buy(pepsi);
      assertTrue("the automat should be empty.", automat.isEmpty());
      assertEquals("the balance should be 0.", 0, automat.balance);
    }
    Run Tests, failed, so
     
    // class Automat
    public void buy(Pepsi pepsi)
    {
      goods.remove(pepsi);
      balance -= Pepsi.PRICE;
    }
    Run Tests again, OK.
     
    那如果沒有投幣就直接買Pepsi呢?再添加一個測試:
     
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithNoBalance()
    {
      try
      {
        automat.buy(pepsi);
        fail("a NoBalanceException was expected when buying a pepsi with no balance.");
      }
      catch (NoBalanceException e)
      {
      }
    }
     
     
    // class NoBalanceException
    public class NoBalanceException extends Exception
    {
      public NoBalanceException(String arg0)
      {
        super(arg0);
      }
    }
     
     
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithTwoYuan()
    {
      automat.put(2);
      try
      {
        automat.buy(pepsi);
      }
      catch (NoBalanceException e)
      {
        fail("a NoBalanceException was throwed.");
      } 
      assertTrue("the automat should be empty.", automat.isEmpty()); 
      assertEquals("the balance should be 0.", 0, automat.balance);
     }

     
    // class Automat
    public void buy(Pepsi pepsi) throws NoBalanceException
    {
      if (balance == 0)
        throw new NoBalanceException("No balance");
      else if (balance >= Pepsi.PRICE)
      {
        goods.remove(pepsi);
        balance -= Pepsi.PRICE;
      }
    }
     
    運(yùn)行測試,綠色!
    接下來投1塊錢買買看:
     
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithOneYuan()
    {
      automat.put(1);
      try
      {
        automat.buy(pepsi);
        fail("a LackOfBalanceException was expected when buying a pepsi without enough balance.");
      }
      catch (LackOfBalanceException e)
      {
      }
      catch (NoBalanceException e)
      {
        fail("a NoBalanceException was not expected.");
      }
    }
    接下來,為了能使編譯通過,做了一下修改:
    // class LackOfBalanceException
    public class LackOfBalanceException extends Exception
    {
      public LackOfBalanceException(String arg0)
      {
        super(arg0);
      }
    }
    // class Automat
    public void buy(Pepsi pepsi) throws NoBalanceException, LackOfBalanceException
    {
      // ...
    }
     
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithNoBalance()
    {
      // ...
      catch (LackOfBalanceException e)
      {
        fail("a LackOfBalanceException was not expected.");
      }

    }
     
    public void testBuyPepsiWithTwoYuan()
    {
      // ...
      catch (LackOfBalanceException e)
      {
        fail("a LackOfBalanceException was not expected.");
      } 
      // ...
    }

    好,沒有錯誤提示了。編譯,運(yùn)行測試,紅色進(jìn)度條。
    testBuyPepsiWithOneYuan()提示“a LackOfBalanceException was expected when buying a pepsi with no enough balance."
     
    我們修改一下Automat.buy():
    // class Automat
    public void buy(Pepsi pepsi) throws NoBalanceException, LackOfBalanceException
    {
      if (balance == 0)
      {
        throw new NoBalanceException("No balance");
      }
      else if (balance >= Pepsi.PRICE)
      {
        goods.remove(pepsi);
        balance -= Pepsi.PRICE;
      }
      else
        throw new LackOfBalanceException("Lack of Balance");
    }
    測試通過了!小小慶祝一下~
     
    那如果我們投了三塊錢呢?好,試試看:
     
    // class TestAutomatWithOnePepsi
    public void testBuyPepsiWithThreeYuan()
    {
      automat.put(3);
      assertTrue("we can buy pepsi.", automat.canBuy(pepsi));  
      try
      {
        automat.buy(pepsi);
        assertTrue("the automat should be empty.", automat.isEmpty());
        assertEquals("the balance should be 1.", 1, automat.balance);
      }
      catch (Exception e)
      {
        fail("Exception was not expected.");
      }  
    }
     
    編譯,運(yùn)行測試,成功!Yeah!
     
    To be continued...
     
     
    下一集將會更加精彩,敬請期待。
    posted @ 2006-02-25 23:12 Baoquan Inside 閱讀(1764) | 評論 (3)編輯 收藏
    主站蜘蛛池模板: 亚洲综合久久1区2区3区| 久久被窝电影亚洲爽爽爽| 久久精品国产99国产精品亚洲| 伊人久久大香线蕉免费视频| 免费国产a国产片高清| 日本系列1页亚洲系列| 免费国产怡红院在线观看| 国产综合激情在线亚洲第一页 | 久久精品亚洲一区二区三区浴池 | 久久精品国产免费一区| 国产亚洲综合成人91精品| 在线观看免费视频网站色| 亚洲AV综合色区无码一区| 日韩精品久久久久久免费| 亚洲精品线在线观看| 免费v片在线观看视频网站| tom影院亚洲国产一区二区| 在线播放高清国语自产拍免费| 亚洲avav天堂av在线网毛片| 又色又污又黄无遮挡的免费视| 一级**爱片免费视频| 亚洲AV无码成人精品区天堂| 免费无码中文字幕A级毛片| 亚洲中文字幕人成乱码 | 99re热免费精品视频观看| 亚洲国产精品网站在线播放| 亚洲精品高清一二区久久| 三级毛片在线免费观看| 久久丫精品国产亚洲av| 成人黄动漫画免费网站视频| 免费无码一区二区| 色拍自拍亚洲综合图区| 狠狠久久永久免费观看| 久草免费福利在线| 亚洲中文无码av永久| 在线观看亚洲精品福利片| 最近免费中文字幕大全免费| 麻豆亚洲AV成人无码久久精品| 亚洲日韩国产精品第一页一区 | 亚洲 综合 国产 欧洲 丝袜| 久久久国产精品福利免费|