国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

隔離框架

2019-11-14 14:33:30
字體:
來源:轉載
供稿:網友

  前面說了手工創建模擬對象的示例,這一章主要說一下使用模擬框架創建示例。我使用的模擬框架是NSubstitute

1:如何創建偽對象

我們知道手動編寫偽對象顯得很笨拙(當然按照實際情況),那么用隔離框架創建偽對象就會很簡單快速,那么我們先看一幅圖

那么首先我們創建一個個接口

1  public interface IUser2     {3         bool Add(string userName, string realName);4     }
IUser

實現接口

1 public class User:IUser {2         public bool Add(string userName, string realName)3         {4             return true;5         }6     }
User

業務中調用

 1 public class UserManager 2     { 3         public bool Add(string userName, string realName) 4         { 5             if (string.IsNullOrWhiteSpace(userName))throw new ArgumentNullException(userName); 6             if (string.IsNullOrWhiteSpace(realName)) throw new ArgumentNullException(realName); 7  8             if (userName.Length>=0) 9             {10                 return false;11             }12             return GetUser().Add(userName, realName);13         }14 }
UserManager

單元測試

1                 [Test]2         public void Add_Default_CallAdd()3         {4             var fakeUser = Substitute.For<IUser>();5             fakeUser.Add("1", "1").Returns(true);//按照我們的意愿進行返回值            6             Assert.IsTrue(fakeUser.Add("1", "1"));                7         }
Add_Default_CallAdd()

以上是我們輸入2個參數然后按我們意愿返回true;

如果我們不考慮參數呢

那么只需要把參數置為Arg.Any<T>()//T表示參數的類型可以string,int等看下測試結果

 當然返回值一定是按照你預定的類型。比喻bool Add() 返回值必須是一個bool類型的或者拋出異常。

2:When...Do的用法

when do在NSub的用處還是比較廣的。比喻當什么的時候做什么。下面一個例子來看一下

1 [Test]2         public void Add_Default_CallAdd()3         {4             var fakeUser = Substitute.For<IUser>();            5             fakeUser.When(x => x.Add("1", "2")).6                 Do(content => { throw new Exception("fack exception"); });//用when,do表示式,表示當操作這個函數的時候會出現什么后果        7             Assert.Throws<Exception>(() => fakeUser.Add("1","2"));        8         }
When-Do

上面的例子就是當參數是1和2的時候會拋出一個異常。下面看現實的結果

剛剛參數是1和2會拋出一個異常如果是1和3會不會拋出異常呢,我們手動把參數進行修改在看下面效果

我們一看測試通不過,此時說明只有當參數1和2的時候才會拋出異常這樣一來模擬框架也會給我們預定的參數進行一個驗證。

3:很強大的Received()

Received()方法工作很神奇,這個方法在什么對象被調用就會返回和這個對象同樣類型的對象,但實際上就是申明斷言的對象。什么意思呢我們看下面的代碼
測試中的接口和實現方法參考上一篇

 1 [Test] 2         public void RecordLog_EmailServiceThrows_CallEmail() 3         { 4             var stub = Substitute.For<ILogService>(); 5             var mock = Substitute.For<IEmailService>(); 6             stub.When(p => p.ErrorLog(Arg.Any<String>())).Do(a => { throw new ArgumentNullException(); }); 7             var test = new TestUserManager(stub, mock); 8             test.RecordLog("");//觸發             9             mock.Received().SendEmail(Arg.Is("lp"), Arg.Is("subject"), Arg.Is("值不能為 null。"));//保證接受了方法并調用(不可以少一個句號)            10         }
測試

在以上的例子我們可以看出Received()就表示SendEmail被調用并且收獲到SendEmail發送的信息然后進行斷言是否和預定發送的信息保持一致。這個和上一篇說的模擬對象斷言是一樣的。(如果使用模擬對象不要忘記Received)

4:事件應該怎么測試

  •  測試監聽事件的一方
  •  測試觸發事件的一方

4.1:測試監聽事件

定義一個事件的接口

1 public interface IView2     {3         event Action Loaded;4         void Render(string content);5     }
IView

事件相關的代碼并如何觸發事件的

 1 public class PResenter 2     { 3  4         private readonly IView _view; 5  6         public Presenter(IView view) 7         { 8             this._view = view; 9             this._view.Loaded += Onload;//注冊事件10         }11 12         public void Onload()13         {14             _view.Render("Hello World");15         }16     }
Presenter

測試代碼

 1 [Test] 2         public void Ctor_WhenViewIsLoad_CallsViewRender() 3         { 4             var mockView = Substitute.For<IView>(); 5             var p =new Presenter(mockView); 6             mockView.Loaded += Raise.Event<Action>(); 7  8             mockView.Received().Render(Arg.Is<string>(s=>s.Contains("Hello World"))); 9 10         }
Ctor_WhenViewIsLoad_CallsViewRender

Raise.Event表示觸發事件。

最后使用received來測試是否view中的Render是否觸發,如果真的觸發那么接受的參數是否是Hello World。

我們可以模擬一個存根一個一個模擬對象

修改與事件相關的代碼

 1 public class Presenter 2     { 3  4         private readonly IView _view; 5         private readonly ILogService _logService; 6  7         public Presenter(IView view,ILogService logService) 8         { 9             this._view = view;10             this._logService = logService;11             this._view.Loaded += Onload;//注冊事件12             this._view.ErrorOccured += WriteLog;13         }14 15         public void Onload()16         {17             _view.Render("Hello World");18         }19 20         public void WriteLog(string errorContent) {21             _logService.ErrorLog(errorContent);22         }23     }
Presenter

測試代碼

 1     [Test] 2         public void Ctor_WhenViewIsError_CallsLogs() { 3  4             var stubView = Substitute.For<IView>(); 5             var mockLog = Substitute.For<ILogService>(); 6             var p = new Presenter(stubView,mockLog); 7             stubView.ErrorOccured += Raise.Event<Action<string>>("fack error"); 8             mockLog.Received().ErrorLog(Arg.Is<string>(s => s.Contains("fack error"))); 9 10         }
Ctor_WhenViewIsError_CallsLogs

注意:使用存根stubView.ErrorOccured += Raise.Event<Action<string>>("fack error");來觸發事件,然后在用模擬對象查看日志服務是否被正確的調用

4.2:測試事件是否觸發

這個比較簡單,在測試方法內部使用一個匿名委托,手動注冊次方法即可

定義一個變量,當事件觸發改變變量的值即可。

如:bool isTrigger=false;

SomeView=new SomeView();

SomeView.Load+=delegate{isTrigger=true;}

SomeView.觸發事件 然后比對isTrigger的值是否改變。

5:模擬框架的優缺點

  • 優點
    • 容易驗證參數
    • 容易創建偽對象
    • 使用模擬對象的時候比較簡單不用手寫大量代碼
  • 缺點

         測試代碼不可讀

         驗證錯誤的事情

        一個測試可能會有多個模擬對象

       過度指定

NSubstitute的官方文檔很詳細有興趣的可以自己查看動手寫一寫會有更好的效果http://nsubstitute.github.io/help/raising-events/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 多伦县| 开阳县| 富民县| 迭部县| 靖安县| 鄂伦春自治旗| 成安县| 梨树县| 大埔区| 九寨沟县| 绍兴县| 平乡县| 新田县| 大新县| 连州市| 乌什县| 云霄县| 靖边县| 南城县| 扶风县| 嫩江县| 伊春市| 东乌珠穆沁旗| 和平县| 兴山县| 浑源县| 丰县| 新蔡县| 元朗区| 河间市| 门源| 汤阴县| 昆明市| 托克逊县| 贵溪市| 四平市| 都江堰市| 沁水县| 元江| 库伦旗| 治县。|