Dependency Injection - Extract and Override
Extract and Override 是另一種 injection 方式,它幾乎不會改變程式的語意(增加 constructor 的參數或者其他 public 介面等等),寫起來乾淨漂亮。它適合用於模擬回傳值或回傳 stub 或 mock object,不適合用在確認被測試程式與 dependency object 的互動。
Override factory method to inject stub
- 在被測試 class 加入可被繼承並 override 的 factory method 來取得 dependency object。
- 在測試裡新增一個 class 繼承被測試 class,override 該 factory method 回傳 stub object,接著使用測試 class 進行測試。
一樣用例子來看,MyClass
是被測試 class,Foo
是 external dependency。
首先是 Foo
相關的 class:
1 |
|
1 |
|
1 |
|
下面 MyClass
裡 getFoo()
是取得 Foo
的 factory method,是 protected
及 virtual
讓 derived class override。MyClass
其他部份程式都以 getFoo()
取得 instance 使用。
1 |
|
至於要有 member 存 dependency object 還是 factory method 直接 return new Foo()
,我想是依使用情況跟語言而定。用 member 存的好處是不用 new 很多次,對大物件是好的,壞處則是 class 裡可能會有地方直接使用 member 而非 factory method。另一方面,沒有 garbage collection 的語言像 C++,就得存下來不然一直 new 會 leak 啊。
最後是 production 以及 test code。
在 unit test 裡加一個繼承 MyClass
的 class TestableMyClass
,override getFoo()
回傳 stub object。一般 production code 使用 MyClass
,unit test 使用 TestableMyClass
進行對 MyClass
的測試。
1 |
|
如果一個 interface 的 stub 依據測試情境有很多個,例如這邊有 FakeFooForA
跟 FakeFooForB
,會需要多個測試 class 繼承 MyClass
、override factory method 回傳不同 stub,或者對 TestableMyClass
做 inject,讓它能回傳不同的 stub。
模擬假結果
除了在 derived class 裡 override factory method 回傳 stub 外,也可以直接回傳假結果,不需要多抽一個 interface 跟製作 stub。
1 |
|
1 |
|
1 |
|
系列文章
- Dependency Injection - Extract Dependency Object
- Dependency Injection - Constructor and Setter Injection
- Dependency Injection - Extract and Override