這是我的問題,我想嘲笑一個類,它在初始化時創建一個線程,並在銷燬時關閉它。我的模擬課沒有理由實際創建和關閉線程。但是,爲了嘲笑一堂課,我繼承了它。當我創建我的模擬類的新實例時,調用基類構造函數,創建線程。當我的模擬對象被銷燬時,基類析構函數被調用,試圖關閉線程。你如何模擬在C++中使用RAII的類
如何模擬一個RAII類而不必處理實際的資源?
這是我的問題,我想嘲笑一個類,它在初始化時創建一個線程,並在銷燬時關閉它。我的模擬課沒有理由實際創建和關閉線程。但是,爲了嘲笑一堂課,我繼承了它。當我創建我的模擬類的新實例時,調用基類構造函數,創建線程。當我的模擬對象被銷燬時,基類析構函數被調用,試圖關閉線程。你如何模擬在C++中使用RAII的類
如何模擬一個RAII類而不必處理實際的資源?
您改爲製作一個描述類型的接口,並且將真實類和模擬類都從中繼承。所以,如果你有:
class RAIIClass {
public:
RAIIClass(Foo* f);
~RAIIClass();
bool DoOperation();
private:
...
};
你會做一個接口,如:
class MockableInterface {
public:
MockableInterface(Foo* f);
virtual ~MockableInterface();
virtual bool DoOperation() = 0;
};
,並從那裏。
首先,你的課程可能設計得很好,但是它們的測試設計很差,這不一定是不合理的。並非一切都很容易測試。
大概你想使用另一個函數或類,它使用你想模擬的類(否則解決方案是微不足道的)。讓我們稱之爲「用戶」,後者稱爲「模擬」。這裏有一些可能性:
如果您不能修改用戶或Mocked,最後兩個可能是您唯一的追索權。如果您可以修改用戶,並且您認爲將代碼設計爲可測試很重要,那麼您應該在其他任何人之前探索第一個選項。請注意,在使您的代碼具有通用性/靈活性並保持簡單性之間可以進行權衡,這兩者都是令人欽佩的品質。
我使用的一種技術是使用某種形式的裝飾器。你的最終代碼有一個方法,它在堆棧上創建它的實例,然後調用相同的方法,但是在一個指向你的基類的成員上。當該調用返回時,您的方法返回銷燬您創建的實例。
在測試時間,您交換一個模擬,它不會創建任何線程,而只是轉發到您要測試的方法。
class Base{
protected:
Base* decorated;
public:
virtual void method(void)=0;
};
class Final: public Base{
void method(void) { Thread athread; decorated->method(); } // I expect Final to do something with athread
};
class TestBase: public Base{
void method(void) { decorated->method(); }
};
PIMPL方法可能適合你。創建您的Thread類,並帶下一個具體實現。如果將#defines和#ifdefs放在正確的位置,則可以在啓用單元測試時更改實現,這意味着您可以在實際實現和模擬實現之間切換,具體取決於您要實現的目標。
去哪裏呢? RAII類通常按值使用,而不是在堆上分配。它們主要用於處理堆棧中的堆對象以確定生命週期。 [實施例](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization) – zahir 2016-10-20 19:33:50