單元測試——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_