SlideShare a Scribd company logo
1 of 71
Download to read offline
淺談高效撰寫單元測試
- 以 Java為例
By Zen
Aug 2017
Zen 陳嘉豪
● I am from Macau
● 現職 TenMax AdTech Lab 騰學廣告科技
● 第一份工作是Android開發,後投身到web 全端
打雜,現專注於後端開發與測試
● 受 odd-e Daniel、Joseph、Jackson 所啟發,
現在致力於幫助團隊打造更順暢、更貼近成年人
的開發環境
● 新任 TenMax TDD 傳教士
● 寫code以外的興趣: 旅行,跳舞, Capoeira,腳
踏車
2017
Unit Test
主軸
Why test
What to test
地雷誤區
Valid Test
Effective Test
有想過/被問過以下問題嗎?
● 我寫的 Test case 夠嗎?
● 我寫的 Test case 達到測試的目的了嗎?
● 我寫的 Test case 有品質嗎?
● 我寫的 Test case 正確碼? 他也需要被測試嗎?
主軸
Why unit test
What to test地雷誤區
Valid Test
Effective Test
那些看的到的 UI
就算了
還有那些看不到的一堆 db record …
1. Automation
- Continuous Integration (Jenkins, Travis ..)
- Test report ( jacoco, Bug report …)
- 可量化,視覺化
- 不需人工介入
- 人會累、眼殘
Cost of test VS. Feature change
2. high ROI
- 投入開發成本相對少
- 規模小,debug相對容易
- 發現早期錯誤
20% test , kill 80% problem
Integration testAcceptance test Manual testMonkey test
Other tests ...
Unit test
Program
Stress test
Clients / End users
主軸
What to test
地雷誤區
Valid Test
Effective Test
Why unit test
誤區Boom !
讓 test 失去意義,反而成為開發的路障:
● 照著 function 來寫 test
● 時好時壞
● 測不到要害
誤區1 - 為了 function 而寫 test case
function
branch 1
branch 2
branch 3
Solution:
- 先了解SPEC/ requirement
- 不要看著product code來寫
test
誤區2 -時好時壞
● 沒有控制 random 變數
● 沒做好 Isolation
public static void updateSpentCheckpoint(Campaign campaign,
boolean doUpdateUTime) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime currHour = now.truncatedTo(ChronoUnit.HOURS);
//assume that Hourly sync finish
if (!LocalDateTimeUtil.isBeforeMidnight(now)) {
currHour = currHour.minusHours(1);
}
campaign.getCheckpoint().setTime(currHour);
}
Solution:
Wrapper/Boundary
E.g. TimeMachine
A Story
Long long time ago …
有一間電商公司
X
誤區3 - 無法正中要害
X
x
血氣方剛的工程師
Bob:
「交給我去開發
吧!」
public void updateReport(Instant targetHourstamp) {
EbaxHourlyReport ebaxHourlyReport =
Optional.ofNullable(hourlyReportRepository.findByHourstamp(targetHourstamp))
.orElse(new
EbaxHourlyReport(targetHourstamp));
try {
String reportBody = tenMaxAPI.fetchReport(targetHourstamp);
TenMaxHourlyReport tenMaxHourlyReport = parseTenMaxReport(reportBody);
updateRecordFromRemoteReport(tenMaxHourlyReport, ebaxHourlyReport);
hourlyReportRepository.save(ebaxHourlyReport);
}
catch(ParseException e) {
logger.error("update fail from TenMaxReport for hourstamp:{}", targetHourstamp,
e);
}
}
血氣方剛的工程師
Bob:
「我知道我要寫 Test
case !」
Mockito
Most popular Mocking framework for unit
tests written in Java
- Mock / Stub / Spy
- when
- Verify
- doNothing
@RunWith(MockitoJUnitRunner.class)
public class ReportServiceTest {
@InjectMocks
private ReportService service;
@Mock
private HourlyReportRepository hourlyReportRepository;
@Mock
private TenMaxAPI tenMaxAPI;
先寫個成功的 case !
@Test
public void testUpdateReportFromTenmax_Ok() {
// GIVEN
Instant targetHour = Instant.parse("2017-03-25T00:00:00");
when(hourlyReportRepository.findByHourstamp(targetHour)).thenReturn(null);
when(tenMaxAPI.fetchReport(targetHour)).thenReturn(
goodTenMaxReportResponseXmlString());
// WHEN
service.updateReport(targetHour);
// THEN
EbaxHourlyReport expect = new EbaxHourlyReport(targetHour, 100, 200, 300);
Mockito.verify(hourlyReportRepository, times(1)).save(expect);
}
「然後再一個 Fail 的
case 就妥穩了!」
EASY !!!
PowerMockito
A more powerful unit test mocking
framework
● Mock private methods
● Mock static methods
● to let static methods throw exceptions
● Whitebox inject
@Test
public void testUpdateReport_fail_for_receive_incorrect_response() throws Exception {
//GIVEN
Instant targetHour = Instant.parse("2017-03-25T00:00:00");
when(hourlyReportRepository.findByHourstamp(targetHour)).thenReturn(null);
when(tenMaxAPI.fetchReport(targetHour)).thenReturn(badResponseXmlString());
//WHEN
service.updateReport(targetHour);
//THEN
// Bob 發現 PowerMockito驚為天人的強大,馬上使用
PowerMockito.verifyPrivate(service, never())
.invoke("updateRecordFromAdHubReport",
any(),
any());
}
驗證private function? 好像蠻直觀… DONE!
三個月後 ...
TenMax 工程師:
「我更新了格式,
你可以不用轉了」
太棒了!
我馬上改!
public void updateReport(Instant targetHourstamp) {
EbaxHourlyReport ebaxHourlyReport =
Optional.ofNullable(hourlyReportRepository.findByHourstamp(targetHourstamp))
.orElse(new
EbaxHourlyReport(targetHourstamp));
try {
String reportBody = tenMaxAPI.fetchReport(targetHourstamp);
EbaxHourlyReport tenMaxHourlyReport = parseTenMaxReport(reportBody);
//updateRecordFromRemoteReport(tenMaxHourlyReport, ebaxHourlyReport);
hourlyReportRepository.save(ebaxHourlyReport);
}
catch(ParseException e) {
logger.error("update fail from TenMaxReport for hourstamp:{}", targetHourstamp, e);
}
}
How about
the tests?
不要讓 Test
流於形式
● Code coverage report ?
● 給老闆看 ?
要測到要害,提早曝露問題
主軸
What to test
地雷誤區
Valid Test
Effective Test
Why unit test
Motivation
Of function
Function Type
1. 回傳計算結果
● Return value
2. 執行動作
● Interaction
● State changed
● Exception throw
Return result 回傳計算結果
public static boolean isValidXmlFormat(String xmlContent) {
if(//....)
return true;
return false;
}
public HourlyRecord findByHourstamp(Instant targetHourstamp) {
//...
return result;
}
public void updateReport(Instant targetHourstamp) {
EbaxHourlyReport ebaxHourlyReport =
Optional.ofNullable(hourlyReportRepository.findByHourstamp(targetHourstamp))
.orElse(new
EbaxHourlyReport(targetHourstamp));
try {
String reportBody = tenMaxAPI.fetchReport(targetHourstamp);
EbaxHourlyReport tenMaxHourlyReport = parseTenMaxReport(reportBody);
//updateRecordFromRemoteReport(tenMaxHourlyReport, ebaxHourlyReport);
hourlyReportRepository.save(ebaxHourlyReport);
}
catch(ParseException e) {
logger.error("update fail from TenMaxReport for hourstamp:{}", targetHourstamp, e);
Invoke interface
修改狀態
public static void updateLastModified(HourlyRecord record, String stuff) {
record.setUpdateTime(LocalDateTime.now());
record.setLastUpdate(stuff);
//...
}
Throw Exception
public static LocalDate parseDate(String str) throws InvalidDateFormatException {
if(str.contains( /*... */)) {
throw new InvalidDateFormatException("Date format should be yyyy-mm-dd");
}
//... more
return result;
}
private TenMaxHourlyReport parseTenMaxReport(String reportXml) throws ParseException {
if(reportXml.contains("bad xml format")) {
throw new ParseException("unsupport xml format", 0);
}
TenMaxHourlyReport report = new TenMaxHourlyReport();
report.setImpression(100);
report.setRequestCount(1000);
return report;
}
private void updateRecordFromRemoteReport(TenMaxHourlyReport src, EbaxHourlyReport
target) {
target.setRequestCount(src.getRequestCount());
target.setImpreCount(src.getImpression());
// series properties to assign ...
}
Test 在乎的是
結果不在乎過程(private function),
只在乎結果 從input/output 判斷該對 function 做甚麼驗證
主軸
What to test地雷:
- Invalid
- unreasonable test
Valid Test
Effective Test
Why unit test
Valid +
Efficient =
Effective
Valid
Team
Convention
Fast
(IDE support)
其他成員難以理解來不及寫
日後維護困難
Effective
讀code 也是溝通成本
@Test
public void testCloneObject() throws Exception {
//case1
AdsOrder ao1 = null;
AdsOrder ao2 = BeanUtils.cloneObject(ao1);
assertNull(ao2);
//case2
AdsOrder ao3 = MockDataUtils.getAdsOrder();
AdsOrder ao4 = BeanUtils.cloneObject(ao3);
assertEquals(ao3, ao4);
}
@Test
public void
test_cloneObject_WHEN_src_is_null_THEN_target_is_null()
throws IllegalAccessException, InstantiationException {
AdsOrder src = null;
AdsOrder target = BeanUtils.cloneObject(src);
Assertions.assertThat(target).isNull();
}
@Test
public void
test_cloneObject_WHEN_src_isNot_null_THEN_target_is_equalTo_s
rc() throws IllegalAccessException, InstantiationException {
AdsOrder src = MockDataUtils.getAdsOrder();
AdsOrder target = BeanUtils.cloneObject(src);
Assertions.assertThat(target).isEqualTo(src);
}
Convention of test
● Naming of test function
● Construction of test function
● Readable content
● Libraries for test
from Clean Code Ch#9
What makes a clean test?
Three things. Readability, readability, and readability.
Readability is perhaps even more important in unit tests than it is in production
code.
是甚麼造就了一個整潔的測試?
三件事,可讀性、可讀性,還是可讀性。可讀性,在單元測試裡可能比在產品程式裡還
要重要。
Accessory
● JUnit5
@Test
@DisplayName("GIVEN: DB 存在 2016-06-30 09:00:00 的 AdxHourly 資料,和 Hourly 資料 "
+ "WHEN: 呼叫 compareWithHourlyReport THEN: 沒有任何錯誤訊息 ")
void test_compareWithHourlyReport_with_compare_success() {
// TODO ...
}
● JUnit4 - extends BlockJUnit4ClassRunner.class
Readable test name
Accessory #2
Opensource:
● JGiven
● JBehavior
● https://github.com/junit-team/junit4/wiki/Custom-runners
FASTER
● Mindset
● IDE tool
● practice
跟工具混熟點
● Paper & Pen (真的是紙跟筆)=> mind map
● IDE Hot keys (Intellij):
- fix error
- refactor
- run
- re-run
● Code snippet / template
Case1
Case2
Case3
Case4
Practice
&
Practice
&
Practice
寫測試最爽的事
別人submit code
因為我的test case 而
build fail.
進行Refactor 時
每改好一個地方,
就可以馬上驗證
Code coverage
蒸蒸日上
你改壞了!
又綠了!
Conclusion
Why to unit test ?
● 確保程式修改後還能正確運作的能力
● Automation
What to test ?
● Motivation
● 在乎結果,忽略過程 (private function)
● Specification By Example (SBE)
How to boost ?
● Team convention
● Familiar with IDE/tools
● Hotkeys
● Practice & Practice & Practice
學會內功,其他
武功都學得快
JS - mocha.js + chai.js +
sinon.js
Php - phpunit
Question ?
Reference
Clean code
https://github.com/rmsadik/x/blob/master/CleanCode/Clean%20Code.pdf
Agile Testing
http://www.ambysoft.com/essays/agileTesting.html
【TDD】課堂心得與筆記 by James Wang
https://dotblogs.com.tw/jameswang/2017/06/12/174704
Contact me
Email: zen0106(at)gmail.com
Logdown: http://oreo0725-blog.logdown.com/

More Related Content

Similar to 淺談高效撰寫單元測試

Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Robot Media
 
UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)
UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)
UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)
Tobias Schneck
 

Similar to 淺談高效撰寫單元測試 (20)

Tech In Asia PDC 2017 - Best practice unit testing in mobile apps
Tech In Asia PDC 2017 - Best practice unit testing in mobile appsTech In Asia PDC 2017 - Best practice unit testing in mobile apps
Tech In Asia PDC 2017 - Best practice unit testing in mobile apps
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Know
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialJAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
 
Agile mobile
Agile mobileAgile mobile
Agile mobile
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Apex Unit Testing in the Real World
Apex Unit Testing in the Real WorldApex Unit Testing in the Real World
Apex Unit Testing in the Real World
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
 
Testacular
TestacularTestacular
Testacular
 
Getting Started With Testing
Getting Started With TestingGetting Started With Testing
Getting Started With Testing
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
 
1 aleksandr gritsevski - attd example using
1   aleksandr gritsevski - attd example using1   aleksandr gritsevski - attd example using
1 aleksandr gritsevski - attd example using
 
Finding Bugs, Fixing Bugs, Preventing Bugs - Exploiting Automated Tests to In...
Finding Bugs, Fixing Bugs, Preventing Bugs - Exploiting Automated Tests to In...Finding Bugs, Fixing Bugs, Preventing Bugs - Exploiting Automated Tests to In...
Finding Bugs, Fixing Bugs, Preventing Bugs - Exploiting Automated Tests to In...
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean tests
 
Agile Android
Agile AndroidAgile Android
Agile Android
 
UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)
UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)
UI Testing - Selenium? Rich-Clients? Containers? (SwanseaCon 2018)
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 

Recently uploaded

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Recently uploaded (20)

04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 

淺談高效撰寫單元測試