惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
G
Google Developers Blog
雷峰网
雷峰网
WordPress大学
WordPress大学
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Engineering at Meta
Engineering at Meta
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
F
Full Disclosure
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
V
V2EX
C
Cisco Blogs
博客园 - 司徒正美
Project Zero
Project Zero
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
Blog — PlanetScale
Blog — PlanetScale
Scott Helme
Scott Helme
A
About on SuperTechFans
Hugging Face - Blog
Hugging Face - Blog
S
Securelist
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
S
Schneier on Security
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
MongoDB | Blog
MongoDB | Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
T
Threatpost
Recorded Future
Recorded Future
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
The Register - Security
The Register - Security
S
Security Archives - TechRepublic
博客园 - Franky
N
News | PayPal Newsroom
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
W
WeLiveSecurity
A
Arctic Wolf
B
Blog

博客园 - 黃偉榮

Web Project的檔案共用小技巧 IoC的中繼器:CommonServiceLocator UTF8Encoding與BOM Temporary Post Used For Theme Detection (d4b0aefa-c88e-4957-bba7-b367d1bfa042 - 3bfe001a-32de-4114-a6b4-4005b770f6d7) 寫CodedUI時如何尋找控制項的小技巧 Visual Studio 2010 Feature Packs 2之Silverlight自動化測試 [小技巧]Entity Framework強型別Include C#仿Oracle Decode,將ValueType對應成String - 黃偉榮 - 博客园 Visual Studio 單元測試的3種Initialize與Cleanup jQuery套件-檢查頁面的欄位是否有變更 用EventLogReader查詢特殊EventLog jQuery自製Plugin-Bind事件函式時檢查有沒有Bind過 ASP.NET MVC TempData使用心得 Visual Stuiod 自訂檔案比較合并工具 [小技巧]自動化測試時NLog的訊息輸出到測試結果中 小技巧:專案切換32與64位元組件 Linq小技巧:日期處理 Unit Test小技巧 : DateTime的Stub 解決TFS Build Asp.Net Mvc開啟MvcBuildViews後無法載入組件問題
Moles - Isolation framework for .NET(假.Net)介紹
黃偉榮 · 2010-11-26 · via 博客园 - 黃偉榮

Moles是前陣子91大推薦我用的Mock的Framework,它跟Moq與Rhino.Mocks這類的套件不同,Moq與Rhino.Mocks這類的Mock是對Interface或Abstract Class做Mock,而Moles是Mock整個CLR(Common Language Runtime),破除Moq等Mock套件的限制,非Interface或Abstract Class也可以Mock,而且還可以對Static Method來Mock,如DateTime.Now或File.Open等等Static Method,使原本在開發時不用為了方便測試而過度設計(如小弟之前為了方便測試,把DateTime又加了一層DateTimeProvider,當我看到這Framework後,就覺得我之前的作法非常的無聊,可參考Unit Test小技巧 : DateTime的Stub)。

•什麼是Mock

Mock簡單來說就是作一個假的東西,通常用在單元測試,因為寫單元測試時,難免沒辦法抽的很乾淨,多少會呼叫到別的Method,如寫訂單的處理,其中有呼叫到信用卡API,在寫單元測試不需要也盡可能不要呼叫到信用卡API,所以用Mock把信用卡API變成假的信用卡API,讓訂單的測試可以獨立,Mock的用法與概念當然不只這樣,詳情可以參考:

NOTE:

Mock與Stub都是用來作假物件,只是二個有實作上的差異,簡單來說,Mock是用動態產生的(如用Moq產生),Stub是已經寫好的(如為了測試實作一個Interface),本文統一都叫作Mock,雖然Moles感覺比較像Stub。

•Moq與Moles比較

Moq的Mock原理是動態產生Class,所以它才只能對Interface或Abstract Class,這類可繼承的型別,如對Interface就是動態產生一個實作Interface所有成員的Class,在用Setup來指定成員的內容或回傳值,多半會搭配IoC,讓程式在呼叫其他類別時,改為呼叫Mock的程式。

NOTE:

大部分Mock的Framework如Moq與Rhino Mocks的底層都是使用Castle DynamicProxy,來動態產生Class。

Moles的Mock原理是,在CLR上在建立一個自己的Runtime,測試時是在MoleRuntime上執行,所以原本是直接呼叫如DateTime.Now,改為呼叫Mock的程式。

image

圖一 MoleRuntime的假想圖

Moq與Moles都有適合的使用時機與限制,可參考圖二。

image

圖二 使用Mole與一般Mock的差異 來源:Microsoft Moles Reference Manual

•安裝Moles

Moles

Visual Studio 2010 Moles - Isolation Framework for .NET(x86)

Visual Studio 2010 Moles - Isolation Framework for .NET(x64)

Pex And Moles

Pex - Automated Whitebox Testing for .NET(x86)

x64版目前只在MSDN Suscribers中下載

NOTE:

Pex是一個Code的分析工具,可以產生相關的單元測試,都是同一個團隊開發,他們把二套Framework綁在一起,個人試用的結果,很有趣,但實用性不高。

•實作DateTime.Now的Mock

1.新增測試專案

2.在測試專案中的參考上按右鍵,選Add Moles Assembly for mscorlib,產生mscorlib.moles檔

image

圖三 新增mscorlib.moles檔

當專案中有.moles檔時,編譯會產生其對應的組件

image

圖四 mscorlib.moles檔與其對應的組件

NOTE:

在舊版的Moles中,mscorlib.moles檔的新增是在新增項目時自行輸入組件名稱,新版直接在參考中右鍵新增*.moles,方便很多。

image

圖五 新增.moles已取消從新增項目中新增的方式,因為找不到圖了借用程湘大的圖片一用。

mscorlib是.Net Framework是最基本的函式庫,俗稱Base Class Library(BCL),也就是把專案中的所有參考都刪除,剩下可以用的型別就是在mscorlib.dll中的型別,DateTime也是其一,而所有不同類型專案的mscorlib.dll一定都相同,如WebApplicationSilverlightmscorlib.dll是一致的(這小弟我沒記錯是這樣,如果說錯了請見諒)。

如果想要Mock其他組件在其他組件上按右鍵新增該組件的.moles檔。

image

圖六 新增其他Moles組件

3.於TestMethod中撰寫DateTime的測試,且Mock DateTime並驗證。

[TestMethod]
[HostType("Moles")]
public void TestMethod1()
{
    System.Moles.MDateTime.NowGet = () => { return new DateTime(2010, 1, 1); };

    Assert.AreEqual(new DateTime(2010, 1, 1), DateTime.Now);
}

在TestMethod上增加[HostType("Moles")],讓Visual Studio知道這一個TestMethod,是要用MoleRuntime執行,Mock的方式是用Delegate,如圖四Moles會建立mscorlib的Mock用組件,其邏輯如下:

  • Namespace:最後加上Moles
  • Type:在前加上M
  • Property:後方加上Get或Set
  • Method:後方加上參數的型別
  • Instance:在AllInstances下操作

所以System.DateTime.Now的Mock在System.Moles.MDateTime.NowGet,範例中DateTime.Now就改為Mock的值,而不是現在時間。

4.增加MoledType宣告。

[assembly: Microsoft.Moles.Framework.MoledType(typeof(DateTime))]

在檔案的最上方或AssemblyInfo.cs中加上MoledType的宣告,每一個要Mock的Type都要增加。

5.執行測試,並通過測試。

•已知問題

我在使用Moles版本0.94.51023.0時,有遇到一個問題,就是MoleRuntime無法正確取得測試專案的app.config,我也有在MSDN中詢問別人,得知的訊息是Bug,可參考Can't get data via ConfigurationManager.AppSettings on HostType("Moles"),但山不轉路轉,聰明的方法沒有,笨死人的解決方法到有,MoleRuntime只會抓自己的app.config,所以只要將資料寫在MoleRuntime的app.config中測試時就可以正常讀取資料,只是設定就沒辦法很方便的xCopy,且會所有專案共用一個app.config,最後我只想到切換專案時,手動更換檔案。

image

圖七 各測試專案需要的app.config

Moles的執行檔案路徑在

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.Moles.VsHost.x86.exe

•其他範例

//測試時只用一組固定的Guid
System.Moles.MGuid.NewGuid = () =>
{
    return new Guid("FFEB1621-5016-4F28-94AE-5DB72FC8A23B");
};           

//測試時不需要真的讀實體檔案
System.IO.Moles.MFile.ReadAllTextString = (filePath) =>
{
    return "測試內容";
};

System.Net.Mail.Moles.MSmtpClient.AllInstances.SendMailMessage = (smtp, message) =>
{
    //測試時不真的寄Email
};

•參考資料

Moles - Isolation framework for .NET

程湘之間 - 單元測試(7): 使用 Moles 增加可測試性

Moq

Rhino.Mocks