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

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

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

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

    測試驅(qū)動開發(fā)(TDD, Test Driven Development)是一種很有意思的軟件開發(fā)方式,本集以較小的步伐體驗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計與模式》(Written by Cay Horstmann) Exercise 2.18
     
    設計并實現(xiàn)一個模擬自動售貨機的程序。通過給機器投入正確的硬幣,便可以購買到相應的商品。用戶從一個可用的商品列表中選擇商品、投入硬幣并得到商品。如果沒有足夠的錢幣或由于此商品已銷售完畢,則將硬幣退回。操作員可以重新備并將錢幣取走。
     
     
    場景#1
    地點:同濟大學西南樓
    涉眾:我,空自動售貨機
     
    寢室樓里面剛搬來了一臺空的自動售貨機,那我們來測試一下:
     
    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;
    }
     
    全部保存,運行測試,呵呵,綠色進度條!測試成功!
     
    好,既然我們還沒有投過硬幣,那么余額應該是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;
     
    運行測試,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;
    }
    再運行一次測試,呵呵,又是綠色!
     
    場景#2
    地點:同濟大學西南樓
    涉眾:我,自動售貨機(有一瓶百事可樂)
     
    好消息,樓長在自動售貨機里面放了一瓶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)了,為了運行兩個測試案例,我們來創(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;
      }
    }
     
    編譯成功,運行AutomatTests,紅色進度條。TestEmptyAutomat綠色,TestAutomatWithOnePepsi紅色。呵呵,看來要讓add做點事情了。
     
    // 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();
    }

     
    再次運行AutomatTests,呵呵,綠色!我們喜歡!
     
    好,我們再看看Automat的余額:
     
    // class TestAutomatWithOnePepsi
    public void testBalance()
    {
      assertEquals("the balance should be 0.", 0, automat.balance);
    }
     
    運行一遍測試,Ok。
     
     
    我們還沒有投硬幣,當然不能買百事可樂了:
     
    // class TestAutomatWithOnePepsi
    public void testCanBuyWithoutBalance()
    {
      assertFalse("we cannot buy pepsi without money.", automat.canBuy(pepsi));
    }
    // class Automat
    public boolean canBuy(Pepsi pepsi)
    {
      return false;
    }
     
    我們太喜歡運行測試了,于是又忍不住運行了所有的自動測試(呵呵,實際上我們只需要點擊一個運行按鈕)。又是綠色~
     
    好,如果Pepsi的價格是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)
    {
     
    }
     
    運行測試,綠色。顯然1塊錢買不到百事可樂。那就投2塊錢吧:
     
    // class TestAutomatWithOnePepsi
    public void testCanBuyWithTwoYuan()
    {
      automat.put(2);
      assertTrue("we can not buy pepsi with two yuan.", automat.canBuy(pepsi));
    }
     
    運行測試,紅色進度條,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
     
    迫不及待地點擊了運行按鈕,yeah!終于能買到喜歡的Pepsi了(因為看到了綠色進度條~)。
     
    于是急忙買了一瓶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;
      }
    }
     
    運行測試,綠色!
    接下來投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.");
      } 
      // ...
    }

    好,沒有錯誤提示了。編譯,運行測試,紅色進度條。
    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.");
      }  
    }
     
    編譯,運行測試,成功!Yeah!
     
    To be continued...
     
     
    下一集將會更加精彩,敬請期待。
    posted on 2006-02-25 23:12 Baoquan Inside 閱讀(1762) 評論(3)  編輯  收藏 所屬分類: TDD

    評論

    # re: 測試驅(qū)動開發(fā)案例之自動售貨機(第1集) 2006-02-27 02:56 dev  回復  更多評論   

    你的這個例子存在并發(fā)問題,一個是金額,另一個是商品都有這個問題;另外,一個自動售貨機可能會有幾種商品,這個沒有考慮到

    # re: 測試驅(qū)動開發(fā)案例之自動售貨機(第1集) 2006-02-27 10:32 Baoquan Inside  回復  更多評論   

    @dev
    謝謝你的關(guān)注!我在并發(fā)編程方面幾乎沒有經(jīng)驗,所以例子可能存在你說提到的并發(fā)問題。為了寫這篇文章,我一直在Blog和Eclipse之間換來換去。不過故事才剛剛開始,所以,你提到的“多種商品”問題將在下一集中被解決。

    # re: 測試驅(qū)動開發(fā)案例之自動售貨機(第1集) 2007-09-16 16:48 魚上游  回復  更多評論   

    第2集呢?

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 亚洲成a人片在线观看中文app| 亚洲无线码在线一区观看| 亚洲国产成人久久99精品| 91免费福利精品国产| 久久亚洲精品人成综合网| 99re6在线精品视频免费播放| 久久精品国产亚洲AV果冻传媒| 97国免费在线视频| 久久精品7亚洲午夜a| 国产成人无码区免费网站| 亚洲AV永久无码精品一百度影院| 国产成人AV免费观看| 亚洲卡一卡2卡三卡4卡无卡三 | 亚洲白嫩在线观看| 2020久久精品国产免费| 亚洲日日做天天做日日谢| 日韩在线视频免费看| 亚洲精品黄色视频在线观看免费资源| 亚洲伊人久久成综合人影院| 国产免费拔擦拔擦8X高清在线人| 亚洲一区中文字幕久久| 一二三四在线观看免费高清中文在线观看 | 亚洲欧洲精品成人久久奇米网| 成人免费大片免费观看网站| 亚洲日韩乱码中文无码蜜桃| 成人免费无码大片a毛片软件| 国产精品久久久久久亚洲小说| 亚洲欧洲日产国码一级毛片| 精品无码AV无码免费专区| 久久精品国产99国产精品亚洲| 中文字幕在线免费观看视频| 亚洲男人的天堂在线播放| 毛片a级毛片免费观看品善网| 日韩国产欧美亚洲v片| 亚洲VA中文字幕无码毛片| 无码高潮少妇毛多水多水免费| 人人爽人人爽人人片av免费| 91精品国产亚洲爽啪在线观看| 最新仑乱免费视频| 国产午夜精品免费一区二区三区| 亚洲天堂免费在线|