国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

2023單元測試利器Mockito框架詳解(超詳細~)

這篇具有很好參考價值的文章主要介紹了2023單元測試利器Mockito框架詳解(超詳細~)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

?前言

Mockito?是當前最流行的?單元測試?Mock?框架。采用?Mock?框架,我們可以?虛擬?出一個?外部依賴,降低測試?組件?之間的?耦合度,只注重代碼的?流程與結果,真正地實現(xiàn)測試目的。

正文

什么是Mock

Mock?的中文譯為仿制的,模擬的,虛假的。對于測試框架來說,即構造出一個模擬/虛假的對象,使我們的測試能順利進行下去。

Mock?測試就是在測試過程中,對于某些?不容易構造(如?HttpServletRequest?必須在?Servlet?容器中才能構造出來)或者不容易獲取?比較復雜?的對象(如?JDBC?中的?ResultSet對象),用一個?虛擬?的對象(Mock?對象)來創(chuàng)建,以便測試方法。

為什么使用Mock測試

單元測試?是為了驗證我們的代碼運行正確性,我們注重的是代碼的流程以及結果的正確與否。

對比真實運行代碼,可能其中有一些?外部依賴?的構建步驟相對麻煩,如果我們還是按照真實代碼的構建規(guī)則構造出外部依賴,會大大增加單元測試的工作,代碼也會參雜太多非測試部分的內容,測試用例顯得復雜難懂。

采用?Mock?框架,我們可以?虛擬?出一個?外部依賴,只注重代碼的?流程與結果,真正地實現(xiàn)測試目的。

Mock測試框架的好處

  1. 可以很簡單的虛擬出一個復雜對象(比如虛擬出一個接口的實現(xiàn)類);
  2. 可以配置?mock?對象的行為;
  3. 可以使測試用例只注重測試流程與結果;
  4. 減少外部類、系統(tǒng)和依賴給單元測試帶來的耦合。

Mockito的流程

mock框架,經驗分享,軟件測試,自動化測試,單元測試,自動化測試,測試工程師,軟件測試,Mock

如圖所示,使用?Mockito?的大致流程如下:

  1. 創(chuàng)建?外部依賴?的?Mock?對象, 然后將此?Mock?對象注入到?測試類?中;
  2. 執(zhí)行?測試代碼;
  3. 校驗?測試代碼?是否執(zhí)行正確。

Mockito的使用

在?Module?的?build.gradle?中添加如下內容:

dependencies {
    //Mockito for unit tests
    testImplementation "org.mockito:mockito-core:2.+"
    //Mockito for Android tests
    androidTestImplementation 'org.mockito:mockito-android:2.+'
}

這里稍微解釋下:

  • mockito-core: 用于?本地單元測試,其測試代碼路徑位于?module-name/src/test/java/
  • mockito-android: 用于?設備測試,即需要運行?android?設備進行測試,其測試代碼路徑位于?module-name/src/androidTest/java/
mockito-core最新版本可以在 Maven 中查詢:mockito-core。 mockito-android最新版本可以在 Maven 中查詢:mockito-android

Mockito的使用示例

普通單元測試使用?mockito(mockito-core),路徑:module-name/src/test/java/

這里摘用官網的?Demo:

檢驗調對象相關行為是否被調用

import static org.mockito.Mockito.*;

// Mock creation
List mockedList = mock(List.class);

// Use mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one"); //調用了add("one")行為
mockedList.clear(); //調用了clear()行為

// Selective, explicit, highly readable verification
verify(mockedList).add("one"); // 檢驗add("one")是否已被調用
verify(mockedList).clear(); // 檢驗clear()是否已被調用

這里?mock?了一個?List(這里只是為了用作?Demo?示例,通常對于?List?這種簡單的類對象創(chuàng)建而言,直接?new?一個真實的對象即可,無需進行?mock),verify()?會檢驗對象是否在前面已經執(zhí)行了相關行為,這里?mockedList?在?verify?之前已經執(zhí)行了?add("one")?和?clear()?行為,所以verify()?會通過。

配置/方法行為

// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
// the following prints "first"
System.out.println(mockedList.get(0));
// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));

這里對幾個比較重要的點進行解析:

when(mockedList.get(0)).thenReturn("first")

這句話?Mockito?會解析為:當對象?mockedList?調用?get()方法,并且參數(shù)為?0?時,返回結果為"first",這相當于定制了我們?mock?對象的行為結果(mock LinkedList?對象為?mockedList,指定其行為?get(0),則返回結果為?"first")。

mockedList.get(999)

由于?mockedList?沒有指定?get(999)?的行為,所以其結果為?null。因為?Mockito?的底層原理是使用?cglib?動態(tài)生成一個?代理類對象,因此,mock?出來的對象其實質就是一個?代理,該代理在?沒有配置/指定行為?的情況下,默認返回?空值。

上面的?Demo?使用的是?靜態(tài)方法?mock()?模擬出一個實例,我們還可以通過注解?@Mock?也模擬出一個實例:

@Mock
private Intent mIntent;

@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();

@Test
public void mockAndroid(){
    Intent intent = mockIntent();
    assertThat(intent.getAction()).isEqualTo("com.yn.test.mockito");
    assertThat(intent.getStringExtra("Name")).isEqualTo("Whyn");
}

private Intent mockIntent(){
    when(mIntent.getAction()).thenReturn("com.yn.test.mockito");
    when(mIntent.getStringExtra("Name")).thenReturn("Whyn");
    return mIntent;
}

對于標記有?@Mock,?@Spy,?@InjectMocks?等注解的成員變量的?初始化?到目前為止有?2?種方法:

  1. 對?JUnit?測試類添加?@RunWith(MockitoJUnitRunner.class)
  2. 在標示有?@Before?方法內調用初始化方法:MockitoAnnotations.initMocks(Object)

上面的測試用例,對于?@Mock?等注解的成員變量的初始化又多了一種方式?MockitoRule。規(guī)則?MockitoRule?會自動幫我們調用?MockitoAnnotations.initMocks(this)?去?實例化?出?注解?的成員變量,我們就無需手動進行初始化了。

Mockito的重要方法

實例化虛擬對象

// 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. Not convinced? See here.
verify(mockedList).get(0);
  • 對于所有方法,mock?對象默認返回?null,原始類型/原始類型包裝類?默認值,或者?空集合。比如對于?int/Integer?類型,則返回?0,對于?boolean/Boolean?則返回?false。
  • 行為配置(stub)是可以被復寫的:比如通常的對象行為是具有一定的配置,但是測試方法可以復寫這個行為。請謹記行為復寫可能表明潛在的行為太多了。
  • 一旦配置了行為,方法總是會返回?配置值,無論該方法被調用了多少次。
  • 最后一次行為配置是更加重要的,當你為一個帶有相同參數(shù)的相同方法配置了很多次,最后一次起作用。

參數(shù)匹配

Mockito?通過參數(shù)對象的?equals()?方法來驗證參數(shù)是否一致,當需要更多的靈活性時,可以使用參數(shù)匹配器:

// Stubbing using built-in anyInt() argument matcher
when(mockedList.get(anyInt())).thenReturn("element");
// Stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
when(mockedList.contains(argThat(isValid()))).thenReturn("element");
// Following prints "element"
System.out.println(mockedList.get(999));
// You can also verify using an argument matcher
verify(mockedList).get(anyInt());
// Argument matchers can also be written as Java 8 Lambdas
verify(mockedList).add(argThat(someString -> someString.length() > 5));

參數(shù)匹配器?允許更加靈活的?驗證?和?行為配置。更多?內置匹配器?和?自定義參數(shù)匹配器?例子請參考:ArgumentMatchersMockitoHamcrest

注意:如果使用了參數(shù)匹配器,那么所有的參數(shù)都需要提供一個參數(shù)匹配器。
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
// Above is correct - eq() is also an argument matcher
verify(mock).someMethod(anyInt(), anyString(), "third argument");
// Above is incorrect - exception will be thrown because third argument is given without an argument matcher.

類似?anyObject(),eq()?這類匹配器并不返回匹配數(shù)值。他們內部記錄一個?匹配器堆棧?并返回一個空值(通常為?null)。這個實現(xiàn)是為了匹配?java?編譯器的?靜態(tài)類型安全,這樣做的后果就是你不能在?檢驗/配置方法?外使用?anyObject()eq()?等方法。

校驗次數(shù)

LinkedList mockedList = mock(LinkedList.class);
// Use mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");

// Follow two verifications work exactly the same - times(1) is used by default
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");

// Exact number of invocations verification
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");

// Verification using never(). never() is an alias to times(0)
verify(mockedList, never()).add("never happened");

// Verification using atLeast()/atMost()
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("three times");
verify(mockedList, atMost(5)).add("three times");

校驗次數(shù)方法常用的有如下幾個:

|Method |Meaning| |:------|:-------| |times(n)| 次數(shù)為n,默認為1(times(1))| |never()| 次數(shù)為0,相當于times(0)| |atLeast(n)|最少n次| |atLeastOnce()| 最少一次| |atMost(n)| 最多n次 |

拋出異常

doThrow(new RuntimeException()).when(mockedList).clear();
// following throws RuntimeException
mockedList.clear();

按順序校驗

有時對于一些行為,有先后順序之分,所以,當我們在校驗時,就需要考慮這個行為的先后順序:

// A. Single mock whose methods must be invoked in a particular order
List singleMock = mock(List.class);
// Use a single mock
singleMock.add("was added first");
singleMock.add("was added second");
// Create an inOrder verifier for a single mock
InOrder inOrder = inOrder(singleMock);
// Following will make sure that add is first called with "was added first, then with "was added second"
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");

// B. Multiple mocks that must be used in a particular order
List firstMock = mock(List.class);
List secondMock = mock(List.class);
// Use mocks
firstMock.add("was called first");
secondMock.add("was called second");
// Create inOrder object passing any mocks that need to be verified in order
InOrder inOrder = inOrder(firstMock, secondMock);
// Following will make sure that firstMock was called before secondMock
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");

存根連續(xù)調用

對于同一個方法,如果我們想讓其在?多次調用?中分別?返回不同?的數(shù)值,那么就可以使用存根連續(xù)調用:

when(mock.someMethod("some arg"))
    .thenThrow(new RuntimeException())
    .thenReturn("foo");

// First call: throws runtime exception:
mock.someMethod("some arg");
// Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));
// Any consecutive call: prints "foo" as well (last stubbing wins).
System.out.println(mock.someMethod("some arg"));

也可以使用下面更簡潔的存根連續(xù)調用方法:

when(mock.someMethod("some arg")).thenReturn("one", "two", "three");
注意:存根連續(xù)調用要求必須使用鏈式調用,如果使用的是同個方法的多個存根配置,那么只有最后一個起作用(覆蓋前面的存根配置)。
// All mock.someMethod("some arg") calls will return "two"
when(mock.someMethod("some arg").thenReturn("one")
when(mock.someMethod("some arg").thenReturn("two")

無返回值函數(shù)

對于?返回類型?為?void?的方法,存根要求使用另一種形式的?when(Object)?函數(shù),因為編譯器要求括號內不能存在?void?方法。

例如,存根一個返回類型為?void?的方法,要求調用時拋出一個異常:

doThrow(new RuntimeException()).when(mockedList).clear();
// Following throws RuntimeException:
mockedList.clear();

監(jiān)視真實對象

前面使用的都是?mock?出來一個對象。這樣,當?沒有配置/存根?其具體行為的話,結果就會返回?空類型。而如果使用?特務對象spy),那么對于?沒有存根?的行為,它會調用?原來對象?的方法??梢园?spy?想象成局部?mock

List list = new LinkedList();
List spy = spy(list);

// Optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
// Use the spy calls *real* methods
spy.add("one");
spy.add("two");

// Prints "one" - the first element of a list
System.out.println(spy.get(0));
// Size() method was stubbed - 100 is printed
System.out.println(spy.size());
// Optionally, you can verify
verify(spy).add("one");
verify(spy).add("two");
注意:由于 spy 是局部 mock,所以有時候使用 when(Object) 時,無法做到存根作用。此時,就可以考慮使用 doReturn() | Answer() | Throw() 這類方法進行存根:
List list = new LinkedList();
List spy = spy(list);
// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

spy?并不是?真實對象?的?代理。相反的,它對傳遞過來的?真實對象?進行?克隆。所以,對?真實對象?的任何操作,spy?對象并不會感知到。同理,對?spy?對象的任何操作,也不會影響到?真實對象。

當然,如果使用?mock?進行對象的?局部?mock,通過?doCallRealMethod() | thenCallRealMethod()?方法也是可以的:

// You can enable partial mock capabilities selectively on mocks:
Foo mock = mock(Foo.class);
// Be sure the real implementation is 'safe'.
// If real implementation throws exceptions or depends on specific state of the object then you're in trouble.
when(mock.someMethod()).thenCallRealMethod();

測試驅動開發(fā)

以?行為驅動開發(fā)?的格式使用 //given //when //then 注釋為測試用法基石編寫測試用例,這正是?Mockito?官方編寫測試用例方法,強烈建議使用這種方式測試編寫。

import static org.mockito.BDDMockito.*;

 Seller seller = mock(Seller.class);
 Shop shop = new Shop(seller);

 public void shouldBuyBread() throws Exception {
     // Given
     given(seller.askForBread()).willReturn(new Bread());
     // When
     Goods goods = shop.buyBread();
     // Then
     assertThat(goods, containBread());
 }

自定義錯誤校驗輸出信息

// Will print a custom message on verification failure
verify(mock, description("This will print on failure")).someMethod();
// Will work with any verification mode
verify(mock, times(2).description("someMethod should be called twice")).someMethod();

@InjectMock

構造器,方法,成員變量依賴注入 使用?@InjectMock?注解時,Mockito?會檢查?類構造器,方法或?成員變量,依據(jù)它們的?類型?進行自動?mock。

public class InjectMockTest {
    @Mock
    private User user;
    @Mock
    private ArticleDatabase database;
    @InjectMocks
    private ArticleManager manager;
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Test
    public void testInjectMock() {
        // Calls addListener with an instance of ArticleListener
        manager.initialize();
        // Validate that addListener was called
        verify(database).addListener(any(ArticleListener.class));
    }

    public static class ArticleManager {
        private User user;
        private ArticleDatabase database;

        public ArticleManager(User user, ArticleDatabase database) {
            super();
            this.user = user;
            this.database = database;
        }

        public void initialize() {
            database.addListener(new ArticleListener());
        }
    }

    public static class User {
    }

    public static class ArticleListener {
    }

    public static class ArticleDatabase {
        public void addListener(ArticleListener listener) {
        }
    }
}

成員變量?manager?類型為?ArticleManager,它的上面標識別了?@InjectMocks。這意味著要?mock?出?manager,Mockito?需要先自動?mock?出?ArticleManager?所需的?構造參數(shù)(即:user?和?database),最終?mock?得到一個?ArticleManager,賦值給?manager。

參數(shù)捕捉

ArgumentCaptor?允許在?verify?的時候獲取?方法參數(shù)內容,這使得我們能在?測試過程?中能對?調用方法參數(shù)?進行?捕捉?并?測試

@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Captor
private ArgumentCaptor<List<String>> captor;
@Test
public void testArgumentCaptor(){
    List<String> asList = Arrays.asList("someElement_test", "someElement");
    final List<String> mockedList = mock(List.class);
    mockedList.addAll(asList);

    verify(mockedList).addAll(captor.capture()); // When verify,you can capture the arguments of the calling method
    final List<String> capturedArgument = captor.getValue();
    assertThat(capturedArgument, hasItem("someElement"));
}

Mocktio的局限

  1. 不能?mock?靜態(tài)方法;
  2. 不能?mock?構造器;
  3. 不能?mockequals()?和?hashCode()?方法。

最后感謝每一個認真閱讀我文章的人,看著粉絲一路的上漲和關注,禮尚往來總是要有的,雖然不是什么很值錢的東西,如果你用得到的話可以直接拿走

mock框架,經驗分享,軟件測試,自動化測試,單元測試,自動化測試,測試工程師,軟件測試,Mock

?這些資料,對于從事【軟件測試】的朋友來說應該是最全面最完整的備戰(zhàn)倉庫,這個倉庫也陪伴我走過了最艱難的路程,希望也能幫助到你!凡事要趁早,特別是技術行業(yè),一定要提升技術功底。希望對大家有所幫助…….有需要的小伙伴可以點擊下方小卡片免費領取文章來源地址http://www.zghlxwxcb.cn/news/detail-682809.html

到了這里,關于2023單元測試利器Mockito框架詳解(超詳細~)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 單元測試利器——手把手教你使用Mockito

    作者:京東零售 秦浩然 從你成為開發(fā)人員的那一天起,寫單元測試終究是你逃不開的宿命!那開發(fā)人員為什么不喜歡寫單元測試呢?究其原因,無外乎是依賴。依賴其他的服務、依賴運行的環(huán)境、等等,各種依賴都成為了我們寫單元測試的絆腳石。那現(xiàn)在有個單元測試利器

    2024年02月08日
    瀏覽(27)
  • SpringBoot單元測試--Mockito+Junit5框架使用

    SpringBoot單元測試--Mockito+Junit5框架使用

    作為程序員為了提前發(fā)現(xiàn)代碼bug,優(yōu)化代碼; 通常我們寫完某個功能模塊代碼后都需要寫單元測試對代碼塊進行測試(特別是敏捷開發(fā)中);Java項目最常用的單元測試框架即為Junit(目前最新版本為Junit5),SpringBoot本身也整合了該框架。在寫單元測試時代碼塊中的調到第三方接口方

    2024年02月02日
    瀏覽(23)
  • Mockito單元測試詳解

    依賴: SpringBoot默認的Mock框架是Mockito,和junit一樣,只需要依賴spring-boot-starter-test就可以了 (1)@RunWith 指定運行環(huán)境,例: @RunWith(SpringRunner.class) Junit運行Spring的測試環(huán)境 @RunWith(MockitoJUnitRunner.class) Junit運行Mockito的運行環(huán)境,不會加載springboot上下文 @SpringBootTest 加載springbo

    2023年04月09日
    瀏覽(21)
  • 【單元測試】Mockito使用詳解

    【單元測試】Mockito使用詳解

    一個單元測試應該有如下特點: 應該是自動化的 應該可以快速運行 每個單元測試不應該依賴其它測試的結果和執(zhí)行順序,單元測試框架可以按任意的順序執(zhí)行每個測試 每個單元測試不應該依賴數(shù)據(jù)庫,外部文件,或者任何長時間運行的任務。單元測試應該是獨立的,不應該

    2024年04月15日
    瀏覽(41)
  • Junit5+Mockito單元測試詳解

    Junit5+Mockito單元測試詳解

    1.宏觀層面:AIR原則 A:Automatic(自動化) 全自動執(zhí)行,輸出結果無需人工檢查,而是通過斷言驗證。 I:Independent(獨立性) 分層測試,各層之間不相互依賴。 R:Repeatable(可重復) 可重復執(zhí)行,不受外部環(huán)境( 網絡、服務、中間件等)影響。 2.微觀層面:BCDE原則 B: Bord

    2024年01月17日
    瀏覽(33)
  • 針對mockito框架在單元測試中出現(xiàn)Mybatis-Plus鏈式調用的解決方案

    1、 調用其他service層方法 2、 調用本service層方法 3、其他問題

    2024年01月24日
    瀏覽(25)
  • 單元測試Mockito

    Mockito 1.為什么要mock? mock等于是創(chuàng)建一個虛擬對象(不會去跑真實的),在測試環(huán)境中替換掉真是對象,從而 驗證該對象某些方法的調用情況,調用多少次,參數(shù)等 給對象做一個定義,指定返回結果或者特定的動作 2.什么是mock,stub和spy mock: Mock 對象是一種完全由測試控制

    2024年03月18日
    瀏覽(32)
  • Spring單元測試+Mockito

    Spring單元測試+Mockito

    一,背景 單元測試基本上是開發(fā)逃不過的一個工作內容,雖然往往因為過于無聊,或者過于麻煩,而停止于項目的迭代之中,不了了之了。其實不是開發(fā)們懶,而是上頭要求的測試覆蓋率高,但是又沒有好用的工具,導致工作積壓,最后只能舍棄掉這部分。 最近發(fā)現(xiàn)Spring+

    2024年04月17日
    瀏覽(50)
  • Mockito單元測試基本使用

    Mockito單元測試基本使用

    本文參考: 【碼農教程】手把手教你Mockito的使用 - 掘金 (juejin.cn) java - doReturn().when()與when().thenReturn() - 成長之路 - SegmentFault 思否 單元測試實踐篇:Mock_阿里巴巴淘系技術團隊官網博客的博客-CSDN博客 阿里是如何進行單元測試培訓的?_Hollis Chuang的博客-CSDN博客 【Mockito】Mock

    2024年02月10日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包