class Inner {
public:
void doSomething();
};
class Outer {
public:
Outer(Inner *inner); // Dependency injection.
void callInner();
};
正確的單元測試說我應該有測試爲Inner
。然後,我應該對Outer
進行測試,該測試不使用真實的Inner
而是使用MockInner
,這樣我將對僅添加Outer
的功能執行單元測試,而不是完整的堆棧Outer
/Inner
。
要做到這一點,Googletest似乎暗示轉向Inner
成純抽象類(接口)是這樣的:
// Introduced merely for the sake of unit-testing.
struct InnerInterface {
void doSomething() = 0;
};
// Used in production.
class Inner : public InnerInterface {
public:
/* override */ void doSomething();
};
// Used in unit-tests.
class MockInner : public InnerInterface {
public:
/* override */ void doSomething();
};
class Outer {
public:
Outer(Inner *inner); // Dependency injection.
void callInner();
};
因此,在生產代碼,我會用Outer(new Inner)
;而在測試中,Outer(new MockInner)
。
好的。理論上看起來不錯,但是當我在整個代碼中開始使用這個想法時,我發現自己爲每一個瘋狂的課程創建了一個純粹的抽象類。即使您可以忽略由於不必要的虛擬調度而導致的輕微運行時間性能下降,這也是很多鍋爐式輸入。
另一種方法是使用模板,如下:
class Inner {
public:
void doSomething();
};
class MockInner {
public:
void doSomething();
};
template<class I>
class Outer {
public:
Outer(I *inner);
void callInner();
};
// In production, use
Outer<Inner> obj;
// In test, use
Outer<MockInner> test_obj;
這避免了鍋爐電鍍和不必要的虛擬調度;但是現在我的整個代碼庫都在怪異的頭文件中,這使得無法隱藏源實現(更不用說處理令人沮喪的模板編譯錯誤和長的構建時間)。
這兩種方法,虛擬和模板是進行適當單元測試的唯一方法嗎?有更好的方法來做適當的單元測試嗎?
通過適當的單元測試,我的意思是每個單元測試測試只能由單位推出的功能,但不是單位的依賴性也。
我個人更喜歡工作單元測試和簡單,乾淨,可維護的設計,以堅持單元測試純粹主義者設定的一些理想。 我喜歡這個迴應---保持事物的實用性。 – kirakun 2011-03-24 22:46:38