1. 程式人生 > >單元測試——Mock

單元測試——Mock

【背景】

        單元測試的目標是一次只驗證一個方法,但是倘若遇到這樣的情況:某個方法依賴於其他一些難以操控的東西,諸如網路、資料庫,甚至是微軟最新的股票價格,那我們該怎麼辦?

        要是你的測試依賴於系統的其他部分,甚至是系統的多個其他部分呢?在這種情況下,倘若不小心,你最終可能會發現自己幾乎初始化了系統的每個元件,而這只是為了給一個測試創造足夠的執行環境讓它們可以執行起來。忙乎了大半天,看上去我們好像有點違背了測試的初衷了。這樣不僅僅消耗時間,還給測試過程引入了大量的耦合因素,比如說,可能有人興致沖沖地改變了一個介面或者資料庫的一張表,突然,你那卑微的單元測試的神祕的掛掉了。在這種情況發生幾次之後,即使是最有耐心的開發者也會洩氣,甚至最終放棄所有的測試,那樣的話後果就不能想像了。

【簡介】

         mock就是在測試過程中,對於某些不容易構造或者 不容易獲取的物件,用一個虛擬的物件來建立以便測試的測試方法。

        在實際的面向物件軟體設計中,我們經常會碰到這樣的情況,我們在對現實物件進行構建之後,物件之間是通過一系列的介面來實現。這在面向物件設計裡是最自然不過的事情了,但是隨著軟體測試需求的發展,這會產生一些小問題。舉個例子,使用者A現在拿到一個使用者B提供的介面,他根據這個介面實現了自己的需求,但是使用者A編譯自己的程式碼後,想簡單模擬測試一下,怎麼辦呢?這點也是很現實的一個問題。我們是否可以針對這個介面來簡單實現一個代理類,來測試模擬,期望程式碼生成自己的結果呢?

         幸運的是,有一種測試模式可以幫助我們:mock物件。Mock物件也就是真實物件在除錯期的替代品。

何時使用Mock物件

1)    真實物件具有不可確定的行為(產生不可預測的結果,如股票的行情)

2)    真實物件很難被建立(比如具體的web容器)

3)    真實物件的某些行為很難觸發(比如網路錯誤)

4)    真實情況令程式的執行速度很慢

5)    真實物件有使用者介面

6)    測試需要詢問真實物件它是如何被呼叫的(比如測試可能需要驗證某個回撥函式是否被呼叫了)

7)    真實物件實際上並不存在(當需要和其他開發小組,或者新的硬體系統打交道的時候,這是一個普遍的問題)

如何使用Mock物件

1、使用一個介面來描述這個物件
2、為產品程式碼實現這個介面

3、以測試為目的,在mock物件中實現這個介面

【例項】

下邊我們以一個Demo:其中有一個Reminder()的方法,如果在下午5點之後呼叫該方法,就會播放對應的音訊,我們需要測試其中的Reminder()方法。

這是整個Demo的總體架構:


1、建立產品程式碼類

首先,建立一個介面:Environmental

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Clock
{
    //介面
    public interface Environmental
    {
        //介面中的定義的方法:Now,返回型別為DataTime
         DateTime Now { get; }
       //播放音訊
         void PlayWavFile(string fileName);

    }
}

在產品SystemEnvironment類中,繼承介面,實現介面中的方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Clock
{
    //SystemEnvironment類繼承介面
    public class SystemEnvironment:Environmental 
    {
        // //定義一個私有的變數:when,返回型別為DateTime
        private DateTime when;

        //定義了一個建構函式SystemEnvironment,並傳入了一個when物件,when的型別為DateTime型別
        public SystemEnvironment(DateTime when)
        {
            this.when = when;        
        }

        //具體實現介面中的方法
        public DateTime Now {
            get {
                return DateTime.Now;
            }       
        }

        //重寫playWavFile方法
        public void PlayWavFile(string fileName)
        {
            throw new NotImplementedException();
        }
    }
}

定義一個Checker類,來呼叫介面方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Clock
{
    //定義一個Checker類,來呼叫介面中的方法
    public class Checker
    {

        Environmental env;

        public Checker(Environmental env) 
        {
            this.env = env;
        }
        
        public void Reminder() 
        {
            DateTime Now = env.Now;
            if (Now.Hour >= 17)
            {
                env.PlayWavFile("***.wav");
            }
        }
    }
}

下邊是一個控制檯類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Clock
{
    public class Program
    {
        //控制檯應用程式
        static void Main(string[] args)
        { 
        }

        //定義一個QuittingTime方法
        public void QuittingTime() 
        {
            DateTime when = new DateTime(2015, 3, 6, 15, 00, 0);
            SystemEnvironment se = new SystemEnvironment(when);

            Checker checker = new Checker(se);

            checker.Reminder();
        }
    }
}

2、然後編寫測試類TestClock(需要新增對nunit.framework的引用)

首先,通過建立Mock測試類MockSystemEnvironment類,來繼承介面Environmental 。MockSystemEnvironment類就是用來代替產品程式碼中的SystemEnvironment類。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Clock;

namespace TestClock
{
    public class MockSystemEnvironment:Environmental 
    {
        //定義一個私有的變數:currentTime,返回型別為DateTime
        private DateTime currentTime;

        //定義了一個建構函式MockSystemEnvironment,並傳入了一個when物件,when的型別為DateTime型別
        public MockSystemEnvironment(DateTime when) {
            //將物件when的值賦給上邊定義的私有變數currentTime
            currentTime = when;
        }

        //實現方法Now
        public DateTime Now {
            get {
                return currentTime;
            }
        }

        //定義一個IncrementMinutes方法,作用是:給currentTime這個時間,加上指定的分鐘數,就可以控制Mock物件所返回的日期和時間
        public void IncrementMinutes(int minutes) {
            currentTime = currentTime.AddMinutes(minutes);
        }

        private bool soundWasPlayed = false;
        public void PlayWavFile(string fileName) {
            soundWasPlayed = true;
        }

        public bool CheckAndResetSound() {
            bool value = soundWasPlayed;
            soundWasPlayed = false;
            return value;
        }
    }
}

然後,編寫具體的測試程式碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Clock;

namespace TestClock
{
    [TestFixture ]
    public  class TestChecker
    {
        [Test]
        public void QuittingTime() 
        {
            //建立了一個DateTime物件:When,並給其賦值為2015, 3, 6, 15, 00, 0
            DateTime when = new DateTime(2015, 3, 6, 15, 00, 0);
            MockSystemEnvironment env = new MockSystemEnvironment(when);     
            Checker checker = new Checker(env);

            //在16:45時,鬧鐘不響
            checker.Reminder();
            Assert.IsFalse(env.CheckAndResetSound(), "16:45");

            //現在,在16:45的基礎上加上15分鐘
            env.IncrementMinutes(15);
            checker.Reminder();
            Assert.IsTrue(env .CheckAndResetSound (),"17:00");

        }
    }
}

PS:在具體的測試中,需要根據實際設定時間。

【結語】

    上邊我們通過一個簡單的Demo來介紹了一下Mock,Demo很簡單,但是Mock的複雜之處在於如何在實際專案中去使用。文章中只是介紹了Mock的冰山一角,更多的東西還需要我們去研究、探索。     在專案中如何使用Mock,還需要我們多實踐,多動手去做,實踐出真知!

相關推薦

單元測試---Mock

一行 構造 ica using ike face turn public ber mock測試就是在測試過程中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來創建以便測試的測試方法. 1 using Moq; 2 3 // Assumptions:

基於spring與mockito單元測試Mock對象註入

err else archive ali spro 反射 lse ica sce 轉載:http://www.blogjava.net/qileilove/archive/2014/03/07/410713.html 1.關鍵詞   單元測試、spring、mockito

【C#】【xUnit】【Moq】.NET單元測試Mock框架Moq初探!

在TDD開發模型中,經常是在編碼的同時進行單元測試的編寫,由於現代軟體開發不可能是一個人完成的工作,所以在定義好介面的時候我們就可以進行自己功能的開發(介面不能經常變更),而我們呼叫他人的功能時只需要使用介面即可。 但我們在編寫自己的單元測試並進行功能驗證的時候,如果介面的實現人還沒有完成程式碼怎麼

SpringMVC : Controller層單元測試Mock

程式碼 @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations = { "classpath:applicationContext.

單元測試——Mock

【背景】         單元測試的目標是一次只驗證一個方法,但是倘若遇到這樣的情況:某個方法依賴於其他一些難以操控的東西,諸如網路、資料庫,甚至是微軟最新的股票價格,那我們該怎麼辦?         要是你的測試依賴於系統的其他部分,甚至是系統的多個其他部分呢?在這種情況

單元測試mock框架——jmockit實戰

轉載地址:http://blog.csdn.net/ultrani/article/details/8993364 JMockit是google code上面的一個java單元測試mock專案,她很方便地讓你對單元測試中的final類, JMockit的測試方式可以通過

單元測試之Stub和Mock

下載 我們 並且 試用 sample 註入 mes oge new 單元測試之Stub和Mock FROM:http://www.cnblogs.com/TankXiao/archive/2012/03/06/2366073.html 在做單元測試的時候,我們會發現我

Mock單元測試

多次調用 註入 tor call stream exceptio system ive eth   單元測試的思路是在不涉及依賴的情況下測試代碼,一般是測試service層的方法,但實際的代碼常會涉及到依賴,一個可行的方法就是使用模擬對象來替換依賴對象。 1.使用Mocki

python筆記24-unittest單元測試mock.patch

rom Coding int self. 錯誤 測試用例 方法 org auto 前言 上一篇python筆記23-unittest單元測試之mock對mock已經有初步的認識, 本篇繼續介紹mock裏面另一種實現方式,patch裝飾器的使用,patch() 作為函數裝飾器

單元測試Mock(Moq)

inter 商品 void 簡單 calc 不用 準備 targe ted Mock翻譯為“嘲弄”,其實就是偽造一個對象用於測試。在單元測試中,被測試方法依賴於其他對象時,為了測試簡單一般“偽造”一個這個對象;這樣做的目的: 不用考慮依賴對象的復雜性(方便準備測試數據)

【轉】關於java 單元測試Junit4和Mock的一些總結

原文出處請點選這裡 1. 單元測試的必要性 最近專案有在寫java程式碼的單元測試,然後在思考一個問題,為什麼要寫單元測試??單元測試寫了有什麼用??百度了一圈,如下: 軟體質量最簡單、最有效的保證; 是目的碼最清晰、最有效的文件;

springboot對shiro進行mock單元測試

  環境:junit-5、Spring5.0.x、Spring Boot 2.0.x     以下是用來許可權測試的介面: @ApiOperation("[可接入]分頁查詢管理員") @ApiResponses({@ApiResponse(code

Mock在Python單元測試中的使用

本文講述的是 Python 中 Mock 的使用。 如何執行單元測試而不用考驗你的耐心 很多時候,我們編寫的軟體會直接與那些被標記為“垃圾”的服務互動。用外行人的話說:服務對我們的應用程式很重要,但是我們想要的是互動,而不是那些不想要的副作用,這裡的“不想要”是在自動化測試執行的語境中說的。例如:我

[OpenStack UT] 分析OpenStack中單元測試mock & mox

在社群貢獻OpenStackcode時,會經常短短的幾行程式碼也要新增不少的UT,耗時耗力,mock & mox 是很好的實現隔離的單元測試模組, 理解它們能夠更快的做UT的編碼。 mock & mox:  都是python中用於實現單元測試的module

Python的單元測試unittest中的Mock使用小結

前面一篇博文簡單說了使用unittest.mock對無返回值的函式做單元測試。這裡是更多一些例子的總結。 被測函式中使用到了input需要自動化輸入 #!/usr/bin/env pytho

C++單元測試二:何時Mock及其是與非

什麼時候需要mock 在前面一部分(C++單元測試一:並非看上去那麼簡單——幾個很實際的問題),我遇到的問題是:一個單元測試工程只能測一個被測類(其實前文的後記部分也已指出,其實建立新工程也不是特別必要,可以讓Mock類從被測類繼承,但問題是這是真的Mock嗎?); 那麼,

使用mock進行單元測試

在service層,使用mock來測試程式碼。而不再使用Juint測試 JUint是java單元測試的框架,已經在Eclipse中預設的安裝。目前主流的有JUnit3和JUnit4.JUint3中,測試用例需要繼承TestCase類,JUint4中,測試用例無需繼承Test

junit使用mock objects進行單元測試

上一篇我介紹了使用stub進行單元測試。那麼mock objects和stub有何區別?什麼情況下使用mock objects呢? 下面摘自junit in action書中的解釋: mock objects (或者簡稱為 mocks),非常適用於將某一部分程式碼與其他代問隔離開來,並對

比較完整的junit單元測試之-----mock模擬測試

為什麼需要模擬?    在我們一開始學程式設計時,我們所寫的物件通常都是獨立的。hello world之類的類並不依賴其他的類(System.out除外),也不會操作別的類。但實際上軟體中是充滿依賴關係的。我們會基於service類寫操作類,而service類又是基於資料訪問類(DAOs)的,依

在Python中使用mock模組進行單元測試

為什麼需要Mock 假設現在系統有兩個模型A和B,其中A依賴B(例如A,B都是函式,A函式體內呼叫了B函式),但是B還沒完成,或者根本就不在控制之內;這時候又需要對A的功能進行單獨測試,就需要使用mock物件,模擬出一個假的fake_B模組,雖然這個fake_