而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。
沒有留言 :
張貼留言