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

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

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

    常用鏈接

    統計

    最新評論

    EasyMock 2 使用指南(轉)

    關于單元測試,模擬對象一直是不可缺少的,尤其對于復雜的應用來說。
           這么多的模擬對象框架中,個人覺得比較好用的當屬EasyMock了。當然JMock也不錯。
           下面簡單介紹一下EasyMock 。(基本翻譯EasyMock的文檔,可能有些地方不是很恰當)
         
           EasyMock 2 主要用于給指定的接口提供模擬對象。

    模擬對象只是模擬領域代碼直接的部分行為,能檢測是否他們如定義中的被使用。使用 Mock 對象,來模擬合作接口,有助于隔離測試相應的領域類。

    創建和維持 Mock 對象經常是繁瑣的任務,并且可能會引入錯誤。 EasyMock 2 動態產生 Mock 對象,不需要創建,并且不會產生代碼。

    有利的方面:

    不需要手工寫類來處理 mock 對象。

    支持安全的重構 Mock 對象:測試代碼不會在運行期打斷當重新命名方法或者更改方法參數。

    支持返回值和例外。

    支持檢察方法調用次序,對于一個或者多個 Mock 對象。

    不利的方面: 2.0 僅使用于 java 2 版本 5.0 或者以上
        

        以一個例子來說明如何使用EasyMock:
       假設有一個合作接口Collaborator:
               
                
    package org.easymock.samples;
     
    public interface Collaborator {
        void documentAdded(String title);
        void documentChanged(String title);
        void documentRemoved(String title);
        byte voteForRemoval(String title);
        byte[] voteForRemovals(String[] title);
    }

    我們主要的測試類為:
                
    package org.easymock.samples;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    public class ClassUnderTest {
        private Set<Collaborator> listeners = new HashSet<Collaborator>();
        private Map<String, byte[]> documents = new HashMap<String, byte[]>();
        public void addListener(Collaborator listener) {
            listeners.add(listener);
        }
        public void addDocument(String title, byte[] document) {
            boolean documentChange = documents.containsKey(title);
            documents.put(title, document);
            if (documentChange) {
                notifyListenersDocumentChanged(title);
            } else {
                notifyListenersDocumentAdded(title);
            }
        }
        public boolean removeDocument(String title) {
            if (!documents.containsKey(title)) {
                return true;
            }
            if (!listenersAllowRemoval(title)) {
                return false;
            }
            documents.remove(title);
            notifyListenersDocumentRemoved(title);
            return true;
        }
        public boolean removeDocuments(String[] titles) {
            if (!listenersAllowRemovals(titles)) {
                return false;
            }
            for (String title : titles) {
                documents.remove(title);
                notifyListenersDocumentRemoved(title);
            }
            return true;
        }
        private void notifyListenersDocumentAdded(String title) {
            for (Collaborator listener : listeners) {
                listener.documentAdded(title);
            }
        }
        private void notifyListenersDocumentChanged(String title) {
            for (Collaborator listener : listeners) {
                listener.documentChanged(title);
            }
        }
        private void notifyListenersDocumentRemoved(String title) {
            for (Collaborator listener : listeners) {
                listener.documentRemoved(title);
            }
        }
        private boolean listenersAllowRemoval(String title) {
            int result = 0;
            for (Collaborator listener : listeners) {
                result += listener.voteForRemoval(title);
            }
            return result > 0;
        }
        private boolean listenersAllowRemovals(String[] titles) {
            int result = 0;
            for (Collaborator listener : listeners) {
                result += listener.voteForRemovals(titles);
            }
            return result > 0;
        }
    }

    第一個Mock 對象

    我們將創建test case 并且圍繞此理解相關的EasyMock 包的功能。第一個測試方法,用于檢測是否刪除一個不存在的文檔,不會發通知給合作類。
              
                
    
                
    package org.easymock.samples;
     
    import junit.framework.TestCase;
     
    public class ExampleTest extends TestCase {
     
        private ClassUnderTest classUnderTest;
        private Collaborator mock;
     
        protected void setUp() {
            classUnderTest = new ClassUnderTest();
            classUnderTest.addListener(mock);
        }
     
        public void testRemoveNonExistingDocument() {    
            // This call should not lead to any notification
            // of the Mock Object: 
            classUnderTest.removeDocument("Does not exist");
        }
    }
        對于多數測試類,使用EasyMock 2,我們只需要靜態引入org.easymock.EasyMock的方法。      
                
     
                

    import static org.easymock.EasyMock.*;

    import junit.framework.TestCase;

    public class ExampleTest extends TestCase {

        private ClassUnderTest classUnderTest;

        private Collaborator mock;

       

    }

         

    為了取得Mock 對象,需要:

    l         創建Mock 對象從需要模擬的接口

    l         記錄期待的行為

    l         轉換到Mock對象,replay狀態。

    例如:     
                
     
                
    protected void setUp() {
            mock = createMock(Collaborator.class); // 1
            classUnderTest = new ClassUnderTest();
            classUnderTest.addListener(mock);
        }

     public void testRemoveNonExistingDocument() {
            // 2 (we do not expect anything)
            replay(mock); // 3
            classUnderTest.removeDocument("Does not exist");
        }
      

    在執行第三步后,mock Collaborator接口的Mock對象,并且期待沒有什么調用。這就意味著,如果我們改變ClassUnderTest去調用此接口的任何方法,則Mock對象會拋出AssertionError

            
                
     
                
    java.lang.AssertionError: 
      Unexpected method call documentRemoved("Does not exist"):
        at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
        at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
        at $Proxy0.documentRemoved(Unknown Source)
        at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)
        at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)
        at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)
        ...

    增加行為

           讓我們開始第二個測試。如果documentclassUnderTest增加,我們期待調用
    mock.documentAdded()在Mock對象使用document的標題作為參數:
                
     
                
     public void testAddDocument() {
            mock.documentAdded("New Document"); // 2
            replay(mock); // 3
            classUnderTest.addDocument("New Document", new byte[0]); 
        }
    如果classUnderTest.addDocument("New Document", new byte[0])調用期待的方法,使用錯誤的參數,Mock對象會拋出AssertionError:
                
     
                
    java.lang.AssertionError: 
      Unexpected method call documentAdded("Wrong title"):
        documentAdded("New Document"): expected: 1, actual: 0
        at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
        at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
        at $Proxy0.documentAdded(Unknown Source)
        at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)
        at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)
        at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
        ...

    同樣,如果調用多次此方法,則也會拋出例外:

                
     
                
    java.lang.AssertionError: 
      Unexpected method call documentAdded("New Document"):
        documentAdded("New Document"): expected: 1, actual: 1 (+1)
        at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
        at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
        at $Proxy0.documentAdded(Unknown Source)
        at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)
        at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
        at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
        ...

    驗證行為

           當我們指定行為后,我們將驗證實際發生的。當前的測試將會判斷是否Mock對象會真實調用。可以調用verify(mock)來山正是否指定的行為被調用。

                
     
                
    public void testAddDocument() {
            mock.documentAdded("New Document"); // 2 
            replay(mock); // 3
            classUnderTest.addDocument("New Document", new byte[0]);
            verify(mock);
        }

    如果失敗,則拋出AssertionError

    期待明顯數量的調用

    到現在,我們的測試只是調用一個簡單的方法。下一個測試將會檢測是否已經存在document導致mock.documentChanged()調用。為了確認,調用三次

                
     
                
    public void testAddAndChangeDocument() {
            mock.documentAdded("Document");
            mock.documentChanged("Document");
            mock.documentChanged("Document");
            mock.documentChanged("Document");
            replay(mock);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            verify(mock);
        }

    為了避免重復的mock.documentChanged("Document"),EasyMock提供一個快捷方式。可以通過調用方法expectLastCall().times(int times)來指定最后一次調用的次數。

                
     
                
     public void testAddAndChangeDocument() {
            mock.documentAdded("Document");
            mock.documentChanged("Document");
            expectLastCall().times(3);
            replay(mock);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            verify(mock);
        }

    指定返回值

           對于指定返回值,我們通過封裝expect(T value)返回的對象并且指定返回的值,使用方法andReturn(Object returnValue)于expect(T value).返回的對象。

    例如:

                
     
                
    public void testVoteForRemoval() {
            mock.documentAdded("Document");   // expect document addition
            // expect to be asked to vote for document removal, and vote for it
            expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
            mock.documentRemoved("Document"); // expect document removal
            replay(mock);
            classUnderTest.addDocument("Document", new byte[0]);
            assertTrue(classUnderTest.removeDocument("Document"));
            verify(mock);
        } 
     
        public void testVoteAgainstRemoval() {
            mock.documentAdded("Document");   // expect document addition
            // expect to be asked to vote for document removal, and vote against it
            expect(mock.voteForRemoval("Document")).andReturn((byte) -42);
            replay(mock);
            classUnderTest.addDocument("Document", new byte[0]);
            assertFalse(classUnderTest.removeDocument("Document"));
           verify(mock);
        }
    取代expect(T value)調用,可以通過expectLastCall().來代替
                
     expect(mock.voteForRemoval("Document")).andReturn((byte) 42);

    等同于

                
     
                
    mock.voteForRemoval("Document");
    expectLastCall().andReturn((byte) 42);

    處理例外

    對于指定的例外(更確切的:Throwables)被拋出,由expectLastCall()和expect(T value)返回的對象,提供了方法andThrow(Throwable throwable)。方法不得不被調用記錄狀態,在調用Mock對象后,對于此指定了要拋出的Throwable。


    基本的方法,已經說完了,當然這不能完全說明EasyMock的使用。更多的因素請參考EasyMock的文檔
    http://www.easymock.org/Documentation.html

    posted on 2007-10-24 13:49 九寶 閱讀(262) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 波多野结衣免费一区视频| 国产成人综合亚洲| 午夜精品免费在线观看| 国产亚洲精久久久久久无码AV| 麻豆亚洲AV成人无码久久精品| 在线播放高清国语自产拍免费| 亚洲精品无码久久久久A片苍井空| 国产精品免费观看久久| 久久夜色精品国产噜噜亚洲a| 国产va免费精品观看精品| 亚洲乱码中文论理电影| 操美女视频免费网站| 亚洲欧美第一成人网站7777| 青青青青青青久久久免费观看 | 国产福利视精品永久免费| 亚洲视频在线播放| 99在线精品免费视频九九视| 亚洲国产系列一区二区三区 | 水蜜桃视频在线观看免费播放高清| 2048亚洲精品国产| 久久免费的精品国产V∧| 亚洲精品在线播放视频| 天天摸天天操免费播放小视频| 亚洲日韩一区二区一无码| 免费在线精品视频| 无码一区二区三区免费| 激情亚洲一区国产精品| 四虎影视永久免费观看网址| 国产福利电影一区二区三区,免费久久久久久久精 | 亚洲激情在线视频| 野花高清在线观看免费3中文 | 亚洲国产精品丝袜在线观看| 97在线视频免费公开视频| 亚洲国产精品成人综合色在线婷婷 | 青青草国产免费国产是公开| 亚洲免费观看视频| 美女视频黄a视频全免费| 老司机午夜精品视频在线观看免费| 亚洲AV无码久久精品色欲| 好男人视频社区精品免费| 91免费在线视频|