java單元測試:unit testing best practices
常用技術:stub, mock
常用工具:Junit, TestNG; Jmockit, Powermock, Mockito
單元測試是如何發現bug的
假設有下面的類,可以判斷一個數是不是質數(只有1和本身兩個因數的數):
public class PrimeDecider {
final int number;
public PrimeDecider(int number) {
this.number = number;
}
public boolean isPrime() {
for (int n = 2; n * n <number; n++) {
if (number % n == 0) {
return false;
}
}
return true;
}
}
對應的單元測試
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class PrimDeciderTest {
@Test
public void sample_2_IsPrime() {
PrimeDecider decider = new PrimeDecider(2);
boolean itIsPrime = decider.isPrime();
assertTrue(itIsPrime);
}
@Test
public void sample_17_IsPrime() {
PrimeDecider decider = new PrimeDecider(17);
boolean itIsPrime = decider.isPrime();
assertTrue(itIsPrime);
}
@Test
public void sample_10_IsNotPrime() {
PrimeDecider decider = new PrimeDecider(10);
boolean itIsPrime = decider.isPrime();
assertFalse(itIsPrime);
}
@Test
public void sample_9_IsNotPrime() {
PrimeDecider decider = new PrimeDecider(9);
boolean itIsPrime = decider.isPrime();
assertFalse(itIsPrime);
}
}
執行結果發現sample_9_IsNotPrime是失敗的,原因是PrimeDecider程式碼有BUG,少了一個等號, 修復的方法是修改判斷質數的迴圈那個算數:
public boolean isPrime() {
for (int n = 2; n * n <=number; n++) {
if (number % n == 0) {
return false;
}
}
return true;
}
哪些需要單元測試?那些不需要單元測試
需要單元測試:
- Core code that is accessed by a lot of other modules
- Code that seems to gather a lot of bugs
- Code that changes by multiple different developers (often to accommodate new requirements)
不需要單元測試(同時需要考慮是不是需要用integration test來覆蓋)
- Other framework libraries (you should assume they work correctly)
- The database (you should assume it works correctly when it is available)
- Other external resources (again you assume they work correctly when available)
- Really trivial code (like getters and setters for example)
- Code that has non deterministic results (Think Thread order or random numbers)
- Code that deals only with UI (e.g. Swing toolkit, Wicket)
- Don’t unit test I/O. I/O is for integrations. Use integration tests, instead.
Stub VS. Mock
區別
樁模組用來模擬被測試的模組所呼叫的模組。驅動模組用來呼叫被測模組,模擬使用者行為。
用例子演示stub和mock的區別
有一個介面:
public interface Service {
// Get real data from database for example.
List findLanguages();
}
有個依賴介面的類,其中有如下程式碼
public CallService(Service service) {
this.service = service;
}
public List findLanguagesWithA() {
List languages = new ArrayList();
for (String s : service.findLanguages()) {
if (s.contains("a"))
languages.add(s);
}
return languages;
}
使用stub測試
打了一個樁(stub), 隔離對Service 介面的依賴:
@Test
public void whenCallServiceIsStubbed() {
CallService service = new CallService(new StubCallService());
assertTrue(service.findLanguagesWithA().size() == 1);
assertTrue(service.findLanguagesWithA().get(0).equals("Java"));
}
class StubCallService implements Service {
public List findLanguages() {
return Arrays.asList(
new String[] { "Groovy", "Clojure", "Java"});
}
}
使用mock測試
使用EasyMock對service介面進行mock:
@Test
public void whenCallServiceIsMocked() {
Service mock = createControl().createMock(Service.class);
CallService service = new CallService(mock);
expect(mock.findLanguages()).andReturn(Arrays.asList(
new String[] { "Groovy", "Clojure", "Java"}));
replay(mock);
List languages = service.findLanguagesWithA();
assertTrue(languages.size() == 1);
assertTrue(languages.get(0).equals("Java"));
verify(mock);
}
https://dzone.com/articles/testing-without-a-mock-framework
mock工具比較
來自於# JMockit的比較:
參考stackoverflow的說法, 目前比較流行的是JMockit、 PowerMock, 其次是 Mockito.
References
http://callistaenterprise.se/blogg/teknik/2010/11/12/stubs-n-mocks/
https://stackoverflow.com/questions/3459287/whats-the-difference-between-a-mock-stub
https://stackoverflow.com/questions/3459287/whats-the-difference-between-a-mock-stub/17810004#17810004
Test Double - Martin Fowler
Test Double - xUnit Patterns
Mocks Aren't Stubs - Martin Fowler
Command Query Separation - Martin Fowler
https://www.javaworld.com/article/2074508/core-java/mocks-and-stubs---understanding-test-doubles-with-mockito.html
https://www.hostettler.net/blog/2014/05/18/fakes-stubs-dummy-mocks-doubles-and-all-that/
http://www.cnblogs.com/TankXiao/archive/2012/03/06/2366073.html#silimar
https://martinfowler.com/articles/mocksArentStubs.html
http://web.cs.iastate.edu/~smkautz/cs227f14/labs/lab5/page08.html
https://javax0.wordpress.com/2015/02/04/do-not-unit-test-bugs/
https://dzone.com/articles/unit-tests-dont-find-bugs
http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/
https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a
https://zeroturnaround.com/rebellabs/dont-test-blindly-the-right-methods-for-unit-testing-your-java-apps/
https://softwareengineering.stackexchange.com/questions/306277/testing-using-mocking-must-i-mock-all-dependencies-too
https://blog.codecentric.de/en/2017/07/mocks-real-thing-tips-better-unit-testing/
相關文章
- ABAP和Java的單元測試Unit TestJava
- 測試 之Java單元測試、Android單元測試JavaAndroid
- 走進單元測試一:初認Unit Test
- Mobile Web Best Practices 1.0Web
- 使用 React Testing Library 和 Jest 完成單元測試React
- Unit testing frameworkFramework
- Database Unit TestingDatabase
- Testing Flutter apps翻譯-單元測試簡介FlutterAPP
- java中的單元測試Java
- Java單元測試之junitJava
- Data Guard Switchover and Failover Best PracticesAI
- 翻譯:iOS Swift單元測試 從入門到精通 Unit Test和UI測試 UITestiOSSwiftUI
- 單元測試:單元測試中的mockMock
- Java單元測試神器之MockitoJavaMockito
- Java單元測試技巧之PowerMockJavaMock
- 1.13-java單元測試junitJava
- 轉享:Architecting for the Cloud: Best PracticesCloud
- Best Practices for Speeding up Your Web SiteWeb
- 如何單元測試Java的private方法Java
- Java中的單元測試與整合測試最佳實踐Java
- 微軟推出Microsoft Exchange Server Best Practices Analyzer Tool微軟ROSServer
- [iOS單元測試系列]單元測試編碼規範iOS
- 51Testing系列叢書:網際網路單元測試及實踐
- Java單元測試之JUnit 5快速上手Java
- Java Junit單元測試(入門必看篇)Java
- Flutter 單元測試Flutter
- Go單元測試Go
- 單元測試工具
- iOS 單元測試iOS
- 前端單元測試前端
- golang 單元測試Golang
- PHP 單元測試PHP
- phpunit單元測試PHP
- JUnit單元測試
- unittest單元測試
- Junit 單元測試.
- 單元測試真
- The Art of Unit Testing: with examples in C#C#