2016-04-03 49 views
4

我的問題是關於測試一個實現了很多接口的類。例如,我有這個類:我們如何測試一個類實現了很多接口?

public class ServiceControllerImpl extends ServiceController implements IDataChanged, IEventChanged { 

} 

現在有兩種測試方法。首先是對具體課程直接進行測試。這意味着對象類型是具體類而不是接口。

public class ServiceControllerImplTest { 
    ServiceControllerImpl instance; 
    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     // you can bring this instance anywhere 
    } 
} 

第二種方法是僅在接口上進行測試。我們必須將此對象轉換爲它實現的所有接口。

public class ServiceControllerImplTest { 
    ServiceController instance;  // use interface here 
    IDataChanged dataChangeListener; 

    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     dataChangeListener = (IDataChanged) instance; 
     // instance and dataChangeListener "look like" two different object. 
    } 
} 

我傾向於第二種方案,因爲也許在將來,我們可以改變它實現了與其他對象的接口,因此,使用具體類可能會導致在未來的測試失敗。我不知道這個問題的最佳做法。

謝謝:)

+2

對於測試您在接口類型上測試的接口。所以你的第二個解決方案基本上就是要走的路。 – JayC667

+1

我確定上面的評論給出了答案,但你的問題需要澄清一點。當你寫'dataChangeListener =(IDataChanged)dataChangeListener;'你的意思是'dataChangeListener =(IDataChanged)實例;',對吧? –

+0

@DaveSchweisguth是的。我編輯過。非常感謝。 – hqt

回答

1

我更喜歡第二個解決方案,因爲在現實中,也許在將來,我們可以改變它實現了與其他對象的接口,讓使用武力具體的課程可能會導致未來的失敗測試。

我想它會導致失敗的測試無論如何,因爲你通常測試的斷言是真實的還是錯誤的。問題是:這些測試是否適用於任何IDataChanged或這些聲明是否僅適用於ServiceControllerImpl

如果斷言只適用於ServiceControllerImpl不要緊,如果你使用IDataChanged而不是ServiceControllerImpl,因爲當你使用其他IDataChanged對象必須編輯測試 - 不同的斷言。如果使用其他對象,測試將失敗。

你設置單元測試的方式本身給你一個答案。單元測試通常單獨測試一個類。這意味着你嘲笑環境。但是嘲笑環境意味着你知道你測試的類的依賴關係,這是實現細節。所以你的測試是在實現的基礎上寫的,而不僅僅是接口。

可以編寫只測試抽象api的測試 - 就像一個接口一樣。但是這通常意味着你的測試也是抽象的。例如。

public abstract class SetTest { 

    @Test 
    public void addAlreadyExistentObject(){ 
     Set<String> setUnderTest = createSetUnderTest(); 
     Assert.assertTrue(setUnderTest.isEmpty()); 

     boolean setChanged = setUnderTest.add("Hello"); 
     Assert.assertTrue(setChanged); 

     setChanged = setUnderTest.add("Hello"); 
     Assert.assertFalse(setChanged); 

     Assert.assertEquals(setUnderTest.size(), 1); 

    } 

    protected abstract Set<String> createSetUnderTest(); 

} 

然後,您可以擴展這些抽象測試來測試具體類的API。例如。

public class HashSetTest extends SetTest { 

    @Override 
    protected Set<String> createSetUnderTest() { 
     return new HashSet<String>(); 
    } 
} 

在這種情況下,您可以替換實現,並且測試必須保持綠色。

但是,這裏是另一個抽象api的例子,當替換被測對象時沒有任何意義。 如何爲所有Runnable s寫一個測試?

public class RunnableTest { 

    @Test 
    public void run(){ 
     Runnable runnable = ...; 

     // What to test here? 
     // run is invoked without throwing any runtime exceptions? 
     runnable.run(); 

    } 
} 

正如你可以看到它沒有意義在某些情況下的方式來編寫測試,這樣就可以輕鬆地更換被測對象。

如果api像Set api定義了一個具體的狀態處理,你可以編寫抽象測試來測試這個。

1

JayC667已經正確地回答,最好通過它的超類型(S)中的那些類型定義的方法測試,是指一類。但是我會改變你這樣做一點,以避免鑄造方式:

public class ServiceControllerImplTest { 
    ServiceController controller; 
    IDataChanged dataChangeListener; 

    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     controller = instance; 
     dataChangeListener = instance; 
    } 
} 
相關問題