而Mockito是一個需要下載的工具(下載jar後引入library中使用),它可以很方便地讓我們模擬還未撰寫完成的模組單元(類別還未實作完的類別),用模擬的單元來進行測試。
在單元測試中,我們有時會碰到一個單元要使用另一個單元的情況,例如單元A要使用單元B,而我們想在假設單元B一定正確的前提下測試單元A、或者是單元B根本就還沒實作完成(不過方法介面等要先出來),這時我們就會需要在單元A的測試中模擬出一個虛擬的單元B幫助測試。
在這裡"JUnit + Mockito 單元測試"有不錯的示例與說明可以參考。
我們在這裡演示一個簡單的例子:
有一個有兩個類別,Singer與Song,其中在Singer的建構子中我們注入一個Song給它,並在Singer的sing()方法中呼叫Song的getLyrics(),sing()方去會回傳從getLyrics()得到的lyrics,而lyrics的值就是Song建構子要傳入的參數,兩個類別的內容如下所示。
Singer:
public class Singer { private Song song; private String lyricsPrefix = "I'm Hugo and I'm singing, "; //注入Song到Singer中 public Singer(Song song) { this.song = song; } //獲取lyricsPrefix public String getLyricsPrefix(){ return lyricsPrefix; } //限制無無參數建構子 private Singer() { } public String sing() { //將song.getLyrics()加上前最綴lyricsPrefix並傳回 String lyrics = lyricsPrefix + song.getLyrics(); return lyrics; } }
Song:
public class Song { private String lyrics; public Song(String lyrics) { this.lyrics = lyrics; } public String getLyrics() { return lyrics; } }
正常情況下,即單元B如上述已經實作好的話,我們可以如下用JUnit去測試它,重點在testSinger()測試方法:
import junit.framework.Assert; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class JUnitTest { public JUnitTest() { } //在所有測試執行前執行 @BeforeClass public static void setUpClass() { } //在所有測試執行後執行 @AfterClass public static void tearDownClass() { } //在單個測試前執行 @Before public void setUp() { } //在單個測試後執行 @After public void tearDown() { } @Test public void testSinger(){ String lyrics = "La...,La...,La..."; Song song = new Song(lyrics); Singer singer = new Singer(song); assertEquals(singer.getLyricsPrefix()+lyrics, singer.sing());
} }我們想要確認是否Singer的sing()方法會把我們送進Song的建構子的參數值加上前綴(可用Singer.getLyricsPrefix()得到)後傳回。但如果假設今天Song的內容還未實作或其實有錯,而我們只想確定如果假設Song沒有錯的情況下Singer的類別能不能通過測試,即是說我們現在測試上層的Singer有沒有實作正確,這時就可以使用Mockito的mock()方法來建立一個模擬的Song,並且設定好它的模擬動作。測試的程式碼如下所示:
import junit.framework.Assert; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class JUnitTest { public JUnitTest() { } //在所有測試執行前執行 @BeforeClass public static void setUpClass() { } //在所有測試執行後執行 @AfterClass public static void tearDownClass() { } //在單個測試前執行 @Before public void setUp() { } //在單個測試後執行 @After public void tearDown() { } @Test public void testSinger(){ String lyrics = "La...,La...,La..."; //Song song = new Song(lyrics); //模擬Song Song mockSong = mock(Song.class); //設定模擬的Song的動作:如果被呼叫getLyrics()方法 //就回傳lyrics when(mockSong.getLyrics()).thenReturn(lyrics); Singer singer = new Singer(mockSong); //假設Song的getLyrics()正確的情況下, //Singer的sing()是否正常運作 assertEquals(singer.getLyricsPrefix()+lyrics, singer.sing()); } }以上的程式碼假設了Song的getLyrics()正常運作下,Singer的sing()傳回的應該是Singer.getLyricsPrefix加上Song.getLyrics(),我們可以試著把Song的getLyrics()實作內容改成錯誤的應該可以發現還是能通過測試,因為我們使用的是模擬的mockSong而非真正的Song。
沒有留言 :
張貼留言