問題描述
假設我有實現它的接口和實現類,我想為此編寫單元測試.我應該測試什么接口或Impl?
Suppose I have interface and implementation class that implements it and I want to write unit-test for this. What should I test interface or Impl?
這是一個例子:
public interface HelloInterface {
public void sayHello();
}
public class HelloInterfaceImpl implements HelloInterface {
private PrintStream target = System.out;
@Override
public void sayHello() {
target.print("Hello World");
}
public void setTarget(PrintStream target){
this.target = target;
}
}
所以,我有實現它的 HelloInterface 和 HelloInterfaceImpl.什么是被測單元接口或 Impl?
So, I have HelloInterface and HelloInterfaceImpl that implements it. What is unit-under-test interface or Impl?
我覺得應該是HelloInterface.考慮下面的 JUnit 測試草圖:
I think it should be HelloInterface. Consider following sketch of JUnit test:
public class HelloInterfaceTest {
private HelloInterface hi;
@Before
public void setUp() {
hi = new HelloInterfaceImpl();
}
@Test
public void testDefaultBehaviourEndsNormally() {
hi.sayHello();
// no NullPointerException here
}
@Test
public void testCheckHelloWorld() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream target = new PrintStream(out);
PrivilegedAccessor.setValue(hi, "target", target);
//You can use ReflectionTestUtils in place of PrivilegedAccessor
//really it is DI
//((HelloInterfaceImpl)hi).setTarget(target);
hi.sayHello();
String result = out.toString();
assertEquals("Hello World", result);
}
}
主線實際上是我注釋掉的.
The main line is actually one that I commented out.
((HelloInterfaceImpl)hi).setTarget(target);
方法 setTarget()
不是我的公共接口的一部分,所以我不想不小心 調用它.如果我真的想調用它,我應該花點時間考慮一下.例如,它幫助我發現我真正想做的是依賴注入.它為我打開了整個世界的新機遇.我可以使用一些現有的依賴注入機制(例如 Spring 的),我可以自己模擬它,就像我在代碼中實際所做的那樣,或者采用完全不同的方法.仔細看,準備 PrintSream 沒那么容易,也許我應該改用 mock 對象?
Method setTarget()
is not part of my public interface, so I don't want to accidentally call it. If I really want to call it, I should take a moment and think about it. It helps me, for example, to discover that what I'm really trying to do is dependency injection. It opens for me the whole world of new opportunities. I can use some existing dependency injection mechanism (Spring's, for example), I can simulate it myself as I actually did in my code or to take totally different approach. Take a closer look, preparation of PrintSream wasn't that easy, maybe I should use mock object instead?
編輯:我認為我應該始終關注界面.從我的角度來看, setTarget()
也不是 impl 類的合同"的一部分,它為依賴注入服務.我認為從測試的角度來看,任何 Impl 類的公共方法都應該被認為是私有的.但這并不意味著我忽略了實現細節.
EDIT:
I think I should always focus on the interface. From my point of view setTarget()
is not part of the "contract" of the impl class neither, it serves sally for dependency injection. I think any public method of Impl class should be considered as private from the testing perspective. It doesn't mean that I ignore the implementation details, though.
另請參閱是否應該對私有/受保護方法進行單元測試?
EDIT-2 在多個實現多個接口的情況下,我會測試所有的實現,但是當我在 setUp()
方法中聲明一個變量時我肯定會使用界面.
EDIT-2 In the case of multiple implementationsmultiple interfaces, I would test all of the implementations, but when I declare a variable in my setUp()
method I would definitely use interface.
推薦答案
實現是需要測試的單元.這當然是您要實例化的內容以及包含程序/業務邏輯的內容.
The implementation is the unit that needs to be tested. That is of course what you are instantiating and what contains the program/business logic.
如果您有一個關鍵接口,并且希望確保每個實現都正確地遵守它,那么您可以編寫一個專注于接口并要求傳入實例的測試套件(與任何實現類型無關).
If you had a critical interface and you wanted to make sure every implementation adhered to it properly, then you may write a test suite that focuses on the interface and requires an instance be passed in (agnostic of any implementation type).
是的,將 Mockito 用于 PrintStream 可能會更容易,但可能并不總是可以避免像在此特定示例中那樣使用模擬對象.
Yes, it would probably be easier to use Mockito for PrintStream, it may not always be possible to avoid using a mock object like you did in this specific example.
這篇關于被測單元:Impl 還是 Interface?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!