Mockito是Java的單元測試Mock框架。html
它的logo是一杯古巴最著名的雞尾酒Mojito,java
Mojito雞尾酒,源自古巴的哈瓦那,帶有濃厚的加勒比海風情。數據庫
並不濃烈,可是喝一杯下去,臉上會泛起紅暈,象少女的羞澀。味道很清新,有一點青澀、有點甜蜜。框架
巧的是,我才發現周董的新歌,也叫《Mojito》。哈哈哈。單元測試
Stub和Mock是Test Double類型中的2種。Test Double一共有5種類型,Dummy,Stub,Spy,Mock,Fake。測試
Test Double是測試複製品,用來統稱模擬真實對象的假對象。因使用場景有略微不一樣,而有這5種類型。code
無論你有沒有懵逼,反正我是懵逼了。不着急,慢慢來,先搞懂Stub和Mock。xml
看一個實例,發送郵件,htm
public interface MailService { public void send(Message msg); }
先寫個Stub,對象
public class MailServiceStub implements MailService { private List<Message> messages = new ArrayList<Message>(); public void send(Message msg) { messages.add(msg); } public int numberSent() { return messages.size(); } }
實現Stub的狀態驗證,
class OrderStateTester...
public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); MailServiceStub mailer = new MailServiceStub(); order.setMailer(mailer); order.fill(warehouse); assertEquals(1, mailer.numberSent()); }
只作了簡單的測試,斷言發出了1封郵件。沒有測試是否發送給了對的收件人,或者郵件正文是否正確。不過不影響跟Mock比較。
若是用Mock,會怎麼寫呢?
class OrderInteractionTester...
public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); Mock warehouse = mock(Warehouse.class); Mock mailer = mock(MailService.class); order.setMailer((MailService) mailer.proxy()); mailer.expects(once()).method("send"); warehouse.expects(once()).method("hasInventory") .withAnyArguments() .will(returnValue(false)); order.fill((Warehouse) warehouse.proxy()); }
結合一張圖,就一下全明白了,
添加Maven dependency,
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.3.3</version> <scope>test</scope> </dependency>
如今能夠開始Mock了,先Mock一個List Interface試試,(示例只是玩語法,實際應使用instance)
//Let's import Mockito statically so that the code looks clearer import static org.mockito.Mockito.*; // mock creation List mockedList = mock(List.class); // using mock object mockedList.add("one"); mockedList.clear(); // verification verify(mockedList).add("one"); verify(mockedList).clear();
接着用Mockito來作Stub,淡定,我知道你在懷疑什麼。咱們在實際使用的時候,不要被理論的概念限制了。Mockito爲何不能Stub,Stub不就是模擬外部依賴嘛,模擬了不就是Stub了嘛。
// You can mock concrete classes, not just interfaces LinkedList mockedList = mock(LinkedList.class); // stubbing when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); // following prints "first" System.out.println(mockedList.get(0)); // following throws runtime exception System.out.println(mockedList.get(1)); // following prints "null" because get(999) was not stubbed System.out.println(mockedList.get(999)); // Although it is possible to verify a stubbed invocation, usually it's just redundant // If your code cares what get(0) returns, then something else breaks // (often even before verify() gets executed). // If your code doesn't care what get(0) returns, then it should not be stubbed. verify(mockedList).get(0);
mock默認會返回null,或原始值,或空集合。如int/Integer返回0,boolean/Boolean返回false。
第一杯先打個樣,喝完這杯,還有「三」杯。
參考資料
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
https://martinfowler.com/articles/mocksArentStubs.html
[http://xunitpatterns.com/Test Double.html](http://xunitpatterns.com/Test Double.html)
專一測試,堅持原創,只作精品。歡迎關注公衆號『東方er』
版權申明:本文爲博主原創文章,轉載請保留原文連接及做者。