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

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
+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)

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
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
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
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
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
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?
 
+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...
 

淺談高效撰寫單元測試