Spring Boot下編寫Controller層單元測試(二)

回顧

在前文Spring Boot下編寫Controller層單元測試(一)中,我們用Spring MVC框架寫了一個最簡單的REST接口,其中沒有涉及業務邏輯。
在本文中我將繼續深入,將業務邏輯加入到項目中,并展示如何進行測試。

增加Service層代碼

首先定義一個接口,在我們簡單項目中是否定義接口其實并不重要,但這依然是個好習慣。

public interface IDemoService {
    List<Demo> findAll();
}

增加DemoService實現層代碼

@Service
public class DemoService implements IDemoService{
    @Override
    public List<Demo> findAll() {
        return null;
    }
}

Controller層調用業務邏輯

接下來我們要在Controller層調用demoService

@Controller
@RequestMapping("demos")
public class DemoController {

    private IDemoService demoService;

        @Autowired
        public DemoController(IDemoService demoService) {
                this.demoService = demoService;
        }

    @GetMapping
    public ResponseEntity<List> searchDemo() {
        List<Demo> demoList = demoService.findAll();
        return new ResponseEntity<>(demoList, HttpStatus.OK);
    }
}

修改單元測試

修改完業務代碼之后直接運行原來的測試代碼,會發現拋出NullPointException

異常信息

這是因為測試的searchDemo()方法需要調用demoService對象,而在我們的測試類中沒有創建demoService對象。

@RunWith(MockitoJUnitRunner.class)
public class MockDemoControllerTest {

    private MockMvc mockMvc;

    @InjectMocks
    private DemoController demoController;
    @Mock // 創建一個模擬的demoService對象
    private DemoService demoService;

?

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.standaloneSetup(demoController).build();
    }

    @Test
    public void should_get_demos() throws Exception {
        mockMvc.perform(get("/demos"))
                .andExpect(status().isOk());
    }

}

修改的測試代碼很簡單,只增加了@Mock private DemoService demoService
執行修改后的測試代碼,將會看到我們的測試結果再次變綠。

發生了什么

相比較與前一個版本,發生了什么改變呢?
首先我們測試的類DemoController多了一個依賴的對象demoService,并且在測試的方法中還需要調用demoServicefindAll()方法。但在原來的測試中,demoController對象中并沒有找到所的demoService對象。
為什么增加@Mock private DemoService demoService之后就可以正常運行了?
關鍵要看使用@InjectMocks@Mock這兩個注解后發生了什么。

@InjectMocks與@Mock

private DemoService demoService1 = new DemoService();

/**
* 可以簡單的理解為 增加這個注解后
* 執行了 private DemoService demoService2 = new DemoService();
*/
@Mock 
private DemoService demoService2;

/**
* @InjectMocks注解可以理解為
* 執行了 private DemoController demoController = new DemoController(demoService2);
*/
@InjectMocks
private DemoController demoController;

也就是說,MockitoJUnitRunner執行器在運行前會檢測到使用@InjectMocks@Mock的成員變量,并自動為其創建對象。

總結

本文在創建REST接口的基礎上增加了業務邏輯,更加貼近實際生產環境。針對代碼結構改變,相應改變了測試代碼,解決待測試代碼的依賴問題。
解釋了測試代碼中用到的兩個注解作用,但沒有對其深入展開。
下一篇我將繼續介紹如何測試Controller代碼,并介紹一下其他的測試用法。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容