2014-01-15 50 views
0

我已經分配了將我們的模擬代碼從EasyMock 1樣式升級到EasyMock 2/3樣式的任務(這是關於時間的,給定的EasyMock 1的大部分在2005年被棄用,並在2010年被刪除,但我們仍然在2014年使用它!)。將多參數匹配()從EasyMock 1 ArgumentsMatcher轉換爲EasyMock 2/3 IArgumentMatcher

我已經想通了如何升級大部分事情,但我有很多的麻煩在轉換實施ArgumentsMatcher匹配器(稱爲EasyMock的1.0.1,其中我們用的是ParameterMatcher)一類實施IArgumentMatcher

在EasyMock的1的ArgumentsMatcher,用於匹配)方法的簽名(狀態:

matches(Object[] expected, Object[] actual)

但在EasyMock的用於匹配方法的簽名()三分之二的IArgumentMatcher是:

matches(Object argument)

我從教程中發現一個IArgumentsMatcher,你可以通過將期望的參數移動到構造函數中來轉換匹配器,lik e所以:

public class GenericMatcher implements IArgumentMatcher { 

    private Object expected; 

    public GenericMatcher(Object expected) { 
     this.expected = expected; 
    } 

    public boolean matches(Object actual) { 
     return this.expected.equals(actual); //Or some other comparison 
    } 
} 

這工作正常,但只有當數組傳入包含一個元素。我在代碼中有許多匹配器,它們一次匹配多個元素。例如:

public boolean matches(Object[] expected, Object[] actual) { 
    if (expected[0].equals(actual[0]){ 
     return expected[1].getName().equals(actual[1]).getName()); 
    } 
    else { 
     return false; 
    } 
} 

我不知道如何將其轉換爲IArgumentMatcher。雖然我可以在構造函數中放入多個參數,但IArgumentMatcher接口只聲明match()方法有一個參數,因此我無法進行多重比較。

當然,我繼承的代碼沒有文檔,不幸的是EasyMock文檔似乎有點缺乏實際傳遞到任一版本的匹配方法的內容。那麼,我將如何轉換這個匹配器?

+0

你沒有理由把你傳入的對象作爲'expected'不能是一個數組,雖然在那裏?查看EasyMocks對'ArrayEquals'的實現(在'EasyMock.aryEq()'matcher中使用)可能對此有所幫助。或者,甚至更好,你能用'EasyMock.aryEq()'匹配器來替換你匹配器的所有實例嗎? –

+0

@DanTemple,啊,所以它似乎是我的問題的第一部分是我忘記了一個數組可以作爲一個對象傳入(我以爲它算作一種基本類型)。不過,我不認爲數組通常會傳入'IArgumentMatcher' matches()方法。不幸的是,真正的代碼更復雜,'EasyMock.aryEq()'不足以滿足我需要,因爲一些數組值比較不同。 – Thunderforge

+0

你可能對沒有傳遞給'matches()'方法的數組是正確的。根據'ArrayEquals'中重寫的'matches'方法的外觀,'instanceof'屬性也被檢查用於所有基元數組類型和Object數組。如果符合'instanceof'檢查,則它將使用java utils中的'Arrays.equals()'。如果'instanceof'檢查不符合,它會調用剛剛使用對象相等的super'matches'方法。最終,這聽起來像你正在編寫你自己的匹配器,'ArrayEquals'可能會幫助給出如何去做的想法。 –

回答

2

在仔細研究現有代碼和操縱事物之後,我想清楚發生了什麼。這裏

myMock.find("Testing", new DateSearchCriteria()); 
myControl.setMatcher(new GenericMatcher()); 
myControl.setReturnValue(AppConstants.TODAY); 

兩件事情:

首先,我們退一步到這個匹配是所謂的EasyMock的1代碼首先有兩個論據find方法。其次,只有一個匹配器被分配。通過一些試驗和錯誤,我發現matches()的EasyMock 1 ArgumentMatcher版本接受一個數組是因爲它比較了調用中的所有參數。所以在這種情況下,Object[] expected = ["Testing", new DateSearchCriteria()]。問題示例中的自定義匹配器檢查第一個參數是否相等,第二個參數是否具有相同的名稱,並隱含理解第一個參數是String,第二個參數是DateSearchCriteria。

這不是一個實現匹配器的好方法,因爲如果您進行任何重構,如更改方法簽名或更改DateSearchCriteria的實現,匹配器將會中斷。但是因爲EasyMock 1只允許你爲每種方法設置一個匹配器,所以這是匹配事物的唯一方法。

EasyMock 2和3改進了功能,因此您可以爲每個單獨的參數設置一個匹配器,而不是整個方法一次。這就是爲什麼IArgumentMatcher匹配()現在只需要一個Object而不是一個Object數組;因爲它只是一次檢查一個參數而不是所有參數。所以EasyMock的1以上代碼將是如在EasyMock的2/3如下:

expect(persistenceManager.find(eq("Testing"), eqName(new DateSearchCriteria()))) 
    .setReturnValue(AppConstants.TODAY)); 

的當量()方法是用於內置在EasyMock的平等時匹配。該eqName()方法會像這樣實現了自定義的方法:

public <T> T eqName(T in) { 
    reportMatcher(new NameMatcher(in)); 
    return null; 
} 

而且NameMatcher將通過使相同的檢查,舊的匹配上的說法#1沒有實現:

public class NameMatcher implements IArgumentMatcher { 
    private Object expected; 

    public NameMatcher(Object expected) { 
     this.expected = expected; 
    } 

    @Override 
    public void appendTo(StringBuffer buffer) { 
     buffer.appendTo("Name is \"" + expected.getName() + "\""); 
    } 

    @Override 
    public boolean matches(Object actual) { 
     return expected.getName().equals(actual.getName()); 
    } 
} 

所以要總結一下,多參數match()方法就像在EasyMock 1中一樣,它在輸入數組的每個元素上進行比較,實際上是檢查被嘲笑的方法的每個參數。它正在對每個參數的狀態做出假設,並且如果重構,它很容易中斷。 EasyMock 2改爲使用mat-per-argument而不是per-method。因此,將EasyMock 1 ArgumentsMatcher轉換爲EasyMock 2/3 IArgumentMatcher所需執行的操作是將每個參數匹配基本拆分爲其自己的匹配器。在上面的例子中,舊的匹配器在參數0上測試了相等性,在參數1上測試了相同的名稱。所以相反,當你聲明方法模擬時,你在參數0上放置了一個相等匹配器(這是內置於EasyMock 2/3中的)併爲參數1創建您自己的名稱匹配器。他們不共享匹配器,它們是個性化的,自包含的匹配器。