開篇
好久不發技術博客,今年要撿起來,新年第一篇就從單測的一個小點講起
背景
作爲要禿頭的程序猿,我們每天要寫非常多的單測代碼,但是我們的單測目標更多時候是可以公開調用的Service層代碼或是 Controller層代碼,如果我們想測試Service層中我們悄悄寫的一些 private方法,就有難度了.
如果一個項目是按一定規範開發的,測試代碼一般和業務源碼在不同包中,導致private方法無法在測試包中進行測試.這裏我們就講一個折中的辦法,來測試這些藏在角落裏的私有方法.
Start
首先我們寫一個可測試的簡單用例
package com.example.demo.design.impl;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
/**
* ID生成器
*
* @author :Lingyun
* @date :2020-02-17 17:46
*/
@Slf4j
public class RandomIdGenerator {
private String generate() {
return "我是private";
}
}
改造:第一步
我們知道私有方法在類外是肯定無法訪問的,這時候槓精可能要來了,反射可以啊.
emmm,這種方案我們不考慮,爲了測試我們去寫一套反射實在是一件性價比很低的事情.既然private 方法不能在類外訪問,那我們只能對實現做一點小的改動,比如把private 換成 protected.
protected String generate() {
return "我是private";
}
改造:第二步
我們變更了方法的作用域,但是這樣操作是有風險的,通常private方法中我們並不會寫參數和業務的前置和後置的校驗,更多時候private方法都是代碼的封裝和抽象,我們修改了作用域,其他開發小夥伴在不知情的情況下貿然使用,可能會出各種問題.
在這裏我們可以藉助Guava中提供的一個註解來標明private方法的這次作用域變更的用途@VisibleForTesting,這個註解並不會實際改變方法的作用域,只是起到註釋的作用,來告訴其他小夥伴調用此方法的風險
@VisibleForTesting
protected String generate() {
return "我是private";
}
改造:第三步
這時候如果你以爲這個方法就可以測試了,那你天真了,儘管generate()方法的作用域已經修改爲protected,但是因爲protected的只能包內調用的特性,我們在測試路徑寫的測試方法依然不能正常調用到改方法,比如這樣:
接下來的一點改動就是本篇文章的精華所在了,下面是RandomIdGenerator類的包路徑
package com.example.demo.design.impl;
然後我們在測試路徑下創建一個相同路徑下的測試類 比如這樣:
是不是很神奇,明明測試類和RandomIdGenerator類不在相同的路徑下但是他們的 package 確是一樣的,這時候我們再看測試方法中的generate()調用也不再報錯了.
我們執行以下測試方法,看是否能正常執行
程序可以正常執行,並打印了日誌
End
寫這篇的目的是幫助大家可以用較簡單和較低的成本來測試private方法,網上也有一些測試私有方法的文章,但是大多都是使用反射來實現的,這種方案每次都要去寫一套反射代碼,實用性並不高.至於方法的作用域的變更,只要標識明確清楚,對代碼的影響是可控的.