2013-03-06 43 views
2

我開始爲C/C++項目使用CppUTest。特別是嘲笑擴展聽起來不錯,但我目前正在努力如何以正確的方式設置模擬。假設一個抽象網絡套接字通信的低級別類。CppUTest:如何將更多數據傳遞給特定的模擬調用?

我的第一種方法:

 
size_t CMockSocket::recv(void* buf, size_t len) 
{ 
    return (size_t) mock().actualCall("recv") 
     .withParameter("len", (int) len) 
     .returnValue().getIntValue(); 
} 

設置的期望:

 
mock().expectOneCall("recv") 
    .withParameter("len", 20) 
    .andReturnValue(15); 

到目前爲止好。但我需要的是提供更多數據 - 在這種情況下,我想通過buf指針返回15個字節。我試圖使用.setData()setDataObject()方法。但它看起來像函數將數據存儲在命名變量中,而不是預期的函數調用。因此後續的調用會覆蓋前面的數據,對吧?

我目前的問題是我怎麼能通過額外的返回數據的嘲笑方法?我的第一個意見是創建一個包含返回值(size_t)和數據緩衝區的結果類。就像這樣:

 
class CRecvResults 
{ 
public: 
    size_t m_returnValue; 
    void* m_buffer; 
    CRecvResults(size_t returnValue, void* buffer) : 
    m_returnValue(returnValue), m_buffer(buffer) {} 
    ~CRecvResults() {} 
}; 

size_t CMockSocket::recv(void* buf, size_t len) 
{ 
    CRecvResults* pResults = 
     (CRecvResults*) mock().actualCall("recv") 
     .withParameter("len", (int) len) 
     .returnValue().getPointerValue()); 

    assert(pResults != NULL); 
    assert(buf != NULL); 
    assert(len >= pResults->m_buffer.length()); 
    memcpy(buf, pResults->m_buffer.data(), pResults->m_buffer.length()); 
    return pResults->m_returnValue; 
} 

和期望:

 
char* buffer = "some returning buffer content at least 15 chars long"; 
CRecvResults results(15, buffer); 
mock().expectOneCall("recv") 
     .withParameter("len", 20) 
     .andReturnValue(&results); 

問:這是正確的做法還是我錯過了什麼?我需要緩衝區內容,因爲我需要測試結果解釋器。

我的第二種方法:

 
bool CMockSocket::send(const void* buf, size_t len) 
{ 
    return mock().actualCall("send") 
     .withParameter("len", (int) len) 
     .returnValue().getIntValue(); 
} 

設置的期望:

 
mock().expectOneCall("send") 
    .withParameter("len", 20) 
    .andReturnValue(true); 

在這種情況下,我想驗證buf中輸出數據,由被測代碼生成的。因此我需要將該緩衝區內容(和長度)返回給測試函數。就像這樣:

 
class CSendResults 
{ 
public: 
    bool m_returnValue; 
    char* m_buffer; 
    size_t m_length; 
    CSendResults(bool returnValue, char* buffer, size_t length) : 
    m_returnValue(returnValue), m_buffer(buffer), m_length(length) {} 
    ~CSendResults() {} 
}; 

bool CMockSocket::send(const void* buf, size_t len) 
{ 
    CSendResults* pResults = 
     (CSendResults*) mock().actualCall("send") 
     .returnValue().getPointerValue(); 

    assert(pResults != NULL); 
    assert(buf != NULL); 
    assert(pResults->m_length >= len); 
    memcpy(pResults->m_buffer, buf, len); 
    pResults->m_length = len; 
    return pResults->m_returnValue; 
} 

和期望:

 
char buffer[1024]; 
CSendResults results(true, buffer, sizeof(buffer); 
mock().expectOneCall("send") 
     .withParameter("len", 20) 
     .andReturnValue(&results); 

// further checks for results content... 

這看起來非常難看,用大量的開銷給我。我的問題再次出現:這是正確的方式,還是我錯過了什麼?

我的最後一個問題是:我能測試完全錯誤的方式嗎?請讓我知道你的經驗和做法!

回答

2

一個新的功能已經被添加到CppUTest,它可以讓你指定嘲笑的輸出參數。這是它會是什麼樣子:

{ 
    return (size_t) mock().actualCall("recv") 
     .withOutputParameter("buf", buf) 
     .withParameter("len", (int) len) 
     .returnUnsignedLongIntValueOrDefault(0); 
} 

並期望可以這樣指定:

char buffer[] = "blabla"; 

mock().expectOneCall("recv") 
    .withOutputParameterReturning("buf", buffer, sizeof(buffer)) 
    .withParameter("len", sizeof(buffer)) 
    .andReturnValue(sizeof(buffer)); 

buffer內容將被複制到通過輸出參數模擬的調用者。所以不再需要醜陋的解決方法。

+0

那真是個好消息!我會盡快檢查,看起來像一個乾淨的解決方案。 – Andi 2015-04-29 12:17:53

+0

順便說一句,在哪個版本中增加了這個功能? – Andi 2015-04-29 12:18:21

+0

它存在於3.6版本中。從那以後,有很多改進,所以可能值得看看目前的頭像。 – 2015-04-29 13:42:41

0

我正在使用下面醜陋的解決方法。 我爲返回值定義了一個結構類型,並在我的僞造函數中加上了我需要的額外數據。 我分配並填充一個實例,我調用expectOneCall()並使用「.andReturnValue()」傳遞它。在僞函數中,我用「... returnValue()。getPointerValue()」獲取數據,然後將返回值設置爲struct-> rc,並處理我的其他數據(將其複製/比較爲緩衝區)。在退出假功能之前,結構被釋放。

這樣,所需的附加數據被綁定到函數調用的參數列表。

Foltos

+0

感謝Foltos的評論。我看到我們有類似的方法使用定製的結構/對象。從上個月的經驗來看,我的印象是這種情況不會經常出現。我試圖看看其他xUnit框架如何處理這個問題,但我沒有找到更多的通用解決方案。 – Andi 2013-07-13 09:18:17

相關問題